kinetic-devel/core/genmsg_cpp/genmsg_oct.cpp

966 lines
35 KiB
C++

/*********************************************************************
* Software License Agreement (BSD License)
*
* Copyright (c) 2008, Willow Garage, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Willow Garage, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
********************************************************************/
// author: Rosen Diankov
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <cstdio>
#include <cerrno>
#include <cassert>
#include <stdexcept>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h>
#include <cstdlib>
#include <cstring>
#include "msgspec.h"
#include "utils.h"
using namespace std;
bool g_header_done;
class msg_var
{
public:
string name;
msg_spec *parent;
msg_var(const string &_name, msg_spec *_parent)
: name(_name), parent(_parent) { }
virtual ~msg_var() { }
virtual string oct_decl() = 0;
virtual string length_expr(const string& msgname) = 0;
virtual bool is_fixed_length() = 0;
virtual string oct_ctor(const string& msgname) = 0;
virtual string helper_funcs() { return string(); }
virtual string serialization_code(const string& msgname, int& nExpectedCount) = 0;
virtual string deserialization_code(const string& msgname) = 0;
virtual string oct_type_name() = 0;
virtual vector<msg_spec *> oct_types(vector<msg_spec *>) = 0;
virtual bool is_primitive() { return false; }
virtual string get_fullname(const string& msgname) {
if( name.size() > 0 )
return msgname + string(".") + name;
return msgname;
}
};
class var_complex : public msg_var
{
public:
string type_spec_str, pkg_path, package;
msg_spec *type_spec;
var_complex(const string &_type, const string &_name, msg_spec *_parent)
: msg_var(_name, _parent), type_spec(NULL)
{
package = parent->package;
vector<string> type_vec;
string_split(_type, type_vec, "/");
string spec_name;
if (type_vec.size() >= 2) {
package = type_vec[0];
spec_name = type_vec[1];
}
else
spec_name = type_vec[0];
string spec_file = spec_name + string(".msg");
if (spec_name == "Header")
package = "roslib";
if(_parent->is_root && !rospack_check_dep(g_pkg, package)) {
printf("Error: you're using package %s in a message/service, but you don't "
"declare a dependency on that package. Please add the missing "
"dependency to your manifest.xml.\n", package.c_str());
exit(13);
}
pkg_path = rospack_find(package);
if (pkg_path.length() == 0) {
printf("Error: couldn't find package %s which was referenced in the "
"message.\n", package.c_str());
exit(13);
}
spec_file = pkg_path + string("/msg/") + spec_file;
//printf("spec file = [%s]\n", spec_file.c_str());
type_spec_str = package + string("/") + spec_name;
try {
type_spec = new msg_spec(spec_file, package, spec_name, pkg_path);
}
catch(std::runtime_error err) {
printf("Error: \"%s\" is neither a primitive type, nor a derived "
"type that I can find.\n", spec_name.c_str());
exit(13);
}
type_spec->class_name = package + string("_") + spec_name;
}
virtual string oct_decl()
{
return string(" ") + oct_type_name() + string(" ") + name;
}
virtual string oct_type_name() { return type_spec->class_name; }
virtual string length_expr(const string& msgname)
{
stringstream ss;
if( is_fixed_length() )
if( name.size() > 0 )
ss << get_fullname(msgname) << string(".serializationLength_(") << get_fullname(msgname) << string(")");
else // create a dummy class that can be queried for the length
ss << type_spec->class_name << string("().serializationLength_()");
else
ss << get_fullname(msgname) + string(".serializationLength_(") << get_fullname(msgname) << ")";
return ss.str();
}
virtual bool is_fixed_length()
{
return type_spec->is_fixed_length();
}
virtual string oct_ctor(const string& msgname)
{
return get_fullname(msgname) + string(" = ") + oct_type_name() + string("();\n");
}
virtual string serialization_code(const string& msgname, int& nExpectedCount)
{
stringstream ss;
ss << get_fullname(msgname) << ".serialize_(" << get_fullname(msgname) << ", seq__, fid__);" << endl;
return ss.str();
}
virtual string deserialization_code(const string& msgname)
{
stringstream ss;
ss << get_fullname(msgname) << " = " << type_spec->class_name << "();" << endl;
ss << get_fullname(msgname) << " = " << get_fullname(msgname) << ".deserialize_(" << get_fullname(msgname) << ", fid__);" << endl;
return ss.str();
}
virtual vector<msg_spec *> oct_types(vector<msg_spec *> v)
{
vector<msg_spec *> types = type_spec->cpp_types(v);
bool found = false;
for (vector<msg_spec *>::iterator i = types.begin();
!found && i != types.end(); ++i)
if ((*i)->spec_file == type_spec->spec_file)
found = true;
if (!found)
types.push_back(type_spec);
return types;
}
};
class var_array : public msg_var
{
public:
string eletype;
int len;
msg_var *ele_var;
var_array(const string &_type, const string &_name, msg_spec *_parent)
: msg_var(_name, _parent), len(0)
{
string::size_type open_bracket = _type.find("[");
string::size_type close_bracket = _type.find("]");
eletype = _type.substr(0, open_bracket);
if (close_bracket > open_bracket + 1)
{
string len_str = _type.substr(open_bracket+1,
close_bracket - open_bracket - 1);
len = atoi(len_str.c_str()); // todo: verify this string is all digits
}
ele_var = parent->make_var(eletype, "");
}
virtual string oct_decl()
{
return ele_var->oct_type_name() + string("{} ") + name;
}
virtual string oct_type_name()
{
return (ele_var->is_primitive() && ele_var->is_fixed_length()) ? "array" : "cell";
}
virtual string oct_ctor(const string& msgname)
{
stringstream ss;
if( ele_var->is_primitive() && ele_var->is_fixed_length() ) {
if( len > 0 )
ss << get_fullname(msgname) << " = zeros(" << len << ", 1, '" << ele_var->oct_type_name() << "');" << endl;
else
ss << get_fullname(msgname) << " = [];" << endl;
}
else {
if( len > 0 ) {
ss << get_fullname(msgname) << " = cell(" << len << ", 1);" << endl;
// intialize the values
ss << "for " << name << "_i__ = 1:" << len << endl
<< " " << ele_var->oct_ctor(get_fullname(msgname) + string("{") + name + string("_i__}"))
<< "end" << endl;
}
else
ss << get_fullname(msgname) << " = {};" << endl;
}
return ss.str();
}
virtual string length_expr(const string& msgname)
{
stringstream ss;
if( ele_var->is_fixed_length() ) {
if( len > 0 )
ss << len << " * (" << ele_var->length_expr("") << ")";
else
ss << "4 + numel(" << get_fullname(msgname) << ") * (" << ele_var->length_expr("") << ")";
}
else {
if( len == 0 )
ss << "4 + ";
ss << g_pkg << "_" << g_name << "___sum_array_length__(cellfun(@(" << name << "_elt__) " << ele_var->length_expr(name + string("_elt__")) << ", " << get_fullname(msgname);
if( len > 0 )
ss << "(1:" << len << ")";
ss << "))";
}
return ss.str();
}
virtual bool is_fixed_length()
{
return len && ele_var->is_fixed_length();
}
virtual string serialization_code(const string& msgname, int& nExpectedCount)
{
stringstream ss;
if( len == 0 )
ss << "fwrite(fid__, numel(" << get_fullname(msgname) << "), 'uint32');" << endl;
if( ele_var->is_primitive() && ele_var->is_fixed_length() ) {
if( len > 0 ) {
nExpectedCount += len;
ss << "c__ = c__ + ";
}
ss << "fwrite(fid__, " << get_fullname(msgname);
if( len > 0 )
ss << "(1:" << len << ")";
else
ss << "(:)";
ss << ", '" << ele_var->oct_type_name() << "');" << endl;
}
else {
ss << "for " << name << "_i__ = 1:numel(" << get_fullname(msgname) << ")" << endl << " ";
ss << ele_var->serialization_code(get_fullname(msgname) + string("{") + name + string("_i__}"), nExpectedCount);
ss << "end" << endl;
}
return ss.str();
}
virtual string deserialization_code(const string& msgname)
{
stringstream ss;
if( len == 0 )
ss << "size__ = double(fread(fid__, 1, 'uint32=>uint32'));" << endl;
if( ele_var->is_primitive() && ele_var->is_fixed_length() ) {
ss << get_fullname(msgname);
if( len == 0 )
ss << " = fread(fid__, size__";
else
ss << "(1:" << len << ") = fread(fid__, " << len;
ss << ", '" << ele_var->oct_type_name();
if( ele_var->oct_type_name() == "single" ) // for some reason octave 3.0.0 doesn't support single=>single
ss << "');" << endl;
else
ss << "=>" << ele_var->oct_type_name() << "');" << endl;
}
else {
ss << get_fullname(msgname) << " = cell(";
if( len == 0 )
ss << "size__";
else
ss << len;
ss << ", 1);" << endl;
ss << "for " << name << "_i__ = 1:";
if( len == 0 )
ss << "size__";
else
ss << len;
ss << endl << " " << ele_var->deserialization_code(get_fullname(msgname) + string("{") + name + string("_i__}"));
ss << "end\n";
}
return ss.str();
}
virtual vector<msg_spec *> oct_types(vector<msg_spec *> v)
{
return ele_var->oct_types(v);
}
};
class var_primitive : public msg_var
{
public:
string type;
var_primitive(const string &_type, const string &_name, msg_spec *_parent)
: msg_var(_name, _parent), type(_type) { }
virtual ~var_primitive() { }
virtual string oct_decl()
{
return oct_type_name() + string(" ") + name;
}
virtual string oct_type_name()
{
if (type == "byte" || type == "int8")
return "int8";
else if (type == "char" || type == "uint8" || type == "bool")
return "uint8";
else if (type == "uint16")
return "uint16";
else if (type == "int16")
return "int16";
else if (type == "uint32")
return "uint32";
else if (type == "int32")
return "int32";
else if (type == "uint64")
return "uint64";
else if (type == "int64")
return "int64";
else if (type == "float32")
return "single";
else if (type == "float64")
return "double";
else if (type == "string")
return "string";
else if (type == "time")
return "rosoct_time";
else if (type == "duration")
return "rosoct_duration";
else
return string("\n#error woah! unhandled primitive type ") + type +
string("\n");
}
virtual string length_expr(const string& msgname)
{
if (type == "byte" || type == "char" || type == "uint8" || type == "int8" || type == "bool")
return "1";
else if (type == "uint16" || type == "int16")
return "2";
else if (type == "uint32" || type == "int32")
return "4";
else if (type == "uint64" || type == "int64")
return "8";
else if (type == "float32")
return "4";
else if (type == "float64")
return "8";
else if (type == "time" || type == "duration")
return "8";
else if (type == "string")
return string("4 + numel(") + get_fullname(msgname) + string(")");
else
return "\n#error woah! bogus length_expr in var_primitive\n";
}
virtual bool is_fixed_length()
{
return type != "string";
}
virtual bool is_primitive()
{
return type != "time" && type != "duration";
}
virtual string oct_ctor(const string& msgname)
{
if (type == "string")
return get_fullname(msgname) + string(" = '';\n");
else if (type == "time" || type == "duration") {
return get_fullname(msgname) + string(" = struct('sec',uint32(0),'nsec',uint32(0));\n");
}
else
return get_fullname(msgname) + string(" = ") + oct_type_name() + string("(0);\n");
}
virtual string serialization_code(const string& msgname, int &nExpectedCount)
{
stringstream ss;
if( type == "string") {
ss << "fwrite(fid__, numel(" << get_fullname(msgname) << "), 'uint32');" << endl;
ss << "fwrite(fid__, " << get_fullname(msgname) << ", 'uint8');" << endl;
}
else if (type == "time" || type == "duration") {
ss << "c__ = c__ + fwrite(fid__, " << get_fullname(msgname) << ".sec" << ", 'uint32');" << endl;
ss << "c__ = c__ + fwrite(fid__, " << get_fullname(msgname) << ".nsec" << ", 'uint32');" << endl;
nExpectedCount += 2;
}
else {
nExpectedCount += 1;
ss << "c__ = c__ + fwrite(fid__, " << get_fullname(msgname) << ", '" << oct_type_name() << "');" << endl;
}
return ss.str();
}
virtual string deserialization_code(const string& msgname)
{
stringstream ss;
if( type == "string") {
ss << "size__ = double(fread(fid__, 1,'uint32=>uint32'));" << endl;
ss << get_fullname(msgname) << " = fread(fid__, size__, '*char')';" << endl;
}
else if (type == "time" || type == "duration") {
ss << get_fullname(msgname) << ".sec" << " = fread(fid__,1,'uint32=>uint32');" << endl;
ss << get_fullname(msgname) << ".nsec" << " = fread(fid__,1,'uint32=>uint32');" << endl;
}
else {
ss << get_fullname(msgname) << " = fread(fid__,1,'" << oct_type_name();
if( oct_type_name() == "single" ) // for some reason octave 3.0.0 doesn't support single=>single
ss << "');" << endl;
else
ss << "=>" << oct_type_name() << "');" << endl;
}
return ss.str();
}
virtual vector<msg_spec *> oct_types(vector<msg_spec *> v)
{
return v;
}
};
static string gsub(const string &input , const string &fr,
const string &to)
{
if (input.empty())
return input;
string s(input);
string::size_type to_len = to.length();
string::size_type fr_len = fr.length();
string::size_type loc = 0;
while (string::npos != (loc = s.find(fr, loc)))
{
s.replace(loc, fr_len, to);
loc += to_len;
if (loc >= s.length())
break;
}
return s;
}
class var_constant : public msg_var
{
public:
string type, constant, safe_constant;
var_constant(const string &_type, const string &_name,
const string &_constant, msg_spec *_parent)
: msg_var(_name, _parent), type(_type), constant(_constant),
safe_constant(_constant)
{
safe_constant = gsub(safe_constant, "\\", "\\\\");
safe_constant = gsub(safe_constant, "\"", "\\\"");
}
virtual ~var_constant() { }
virtual string oct_decl()
{
return string("CONST ") + oct_type_name() + string("() ") + name + string(" = ") + constant;
}
virtual string oct_ctor(const string& msgname)
{
return get_fullname(msgname) + string(" = @") + g_pkg + string("_") + g_name + string("_") + name + string(";\n");
}
virtual string oct_type_name()
{
// this version of the function purposefully does not
// include Time or Duration, instead emits a preprocessor error directive
if (type == "char" || type == "uint8" || type == "bool")
return "uint8_t";
else if (type == "byte" || type == "int8")
return "int8_t";
else if (type == "uint16")
return "uint16_t";
else if (type == "int16")
return "int16_t";
else if (type == "uint32")
return "uint32_t";
else if (type == "int32")
return "int32_t";
else if (type == "uint64")
return "uint64_t";
else if (type == "int64")
return "int64_t";
else if (type == "float32")
return "float";
else if (type == "float64")
return "double";
else if (type == "string")
return "std::string";
else
return string("\n#error woah! unhandled primitive type ") + type +
string("\n");
}
virtual string length_expr(const string& msgname) { return "0"; }
virtual bool is_fixed_length() { return true; }
virtual string helper_funcs()
{
stringstream ss;
ss << "function x = " << g_pkg << "_" << g_name << "_" << name << "()" << endl;
ss << "x = " << constant << ";" << endl << endl;
return ss.str();
}
virtual string serialization_code(const string& msgname, int &nExpectedCount) { return string(); }
virtual string deserialization_code(const string& msgname) { return string(); }
virtual vector<msg_spec *> oct_types(vector<msg_spec *> v) { return v; }
};
msg_spec::msg_spec(const string &_spec_file, const string &_package,
const string &_spec_name, const string &_pkg_path,
bool is_filename, bool _is_root)
: spec_file(_spec_file), spec_name(_spec_name), package(_package),
pkg_path(_pkg_path), is_root(_is_root)
{
if (is_filename) {
// parse it
FILE *f = fopen(spec_file.c_str(), "r");
if (!f)
throw std::runtime_error("couldn't open spec file");
if (is_root) {
{
// compute md5sum
string cmd = string("`rospack find roslib`/scripts/gendeps --md5 ") + spec_file;
FILE *md5pipe = popen(cmd.c_str(), "r");
if (!md5pipe)
throw std::runtime_error("couldn't launch gendeps in genmsg_cpp\n");
char md5buf[PATH_MAX];
if (!fgets(md5buf, PATH_MAX, md5pipe))
throw std::runtime_error("couldn't read md5sum pipe in genmsg_cpp\n");
char *md5str = strtok(md5buf, " \t\n");
md5sum = string(md5str);
// call pclose sometime
}
{
std::stringstream ss;
// compute concatenated definition
string cmd = string("`rospack find roslib`/scripts/gendeps --cat ") + spec_file;
FILE *catpipe = popen(cmd.c_str(), "r");
if (!catpipe)
throw std::runtime_error("couldn't launch gendeps in genmsg_cpp\n");
char buf[1024];
while (fgets(buf, 1024, catpipe))
{
std::string str(buf, 1024);
ss << buf;
}
// call pclose sometime
full_definition = ss.str();
}
}
const int LINEBUF_LEN = 1024;
char linebuf[LINEBUF_LEN];
for (int linenum = 1; !feof(f); linenum++) {
if (!fgets(linebuf, LINEBUF_LEN, f))
break; // hit EOF
process_line(linebuf, linenum); // no need for error checking b/c
// they are all fatal
}
fclose(f);
}
else {
vector<string> lines;
string_split(string(spec_file), lines, "\n");
for (size_t i = 0; i < lines.size(); i++) {
lines[i] += "\n";
char linebuf[1024];
strncpy(linebuf, lines[i].c_str(), sizeof(linebuf)-1);
process_line(linebuf, i+1);
//printf("line = [%s]\n", lines[i].c_str());
}
}
}
static string trim_whitespace(string str, const char *extra_ws_chars = "")
{
string ws = " \t\r\n";
ws += extra_ws_chars;
size_t start = str.find_first_not_of(ws);
if (start == string::npos)
return string(); // nothing there but whitespace
size_t end = str.find_first_of(ws, start);
return str.substr(start, end - start);
}
bool msg_spec::process_line(char *linebuf, int linenum)
{
if (strlen(linebuf) == 0 || linebuf[0] == '#')
return true;
// see if the first non-whitespace character is a hash
size_t i;
for (i = 0; i < strlen(linebuf); i++)
if (linebuf[i] != ' ' && linebuf[i] != '\t')
break;
if (i == strlen(linebuf) || linebuf[i] == '\n')
return true; // this line was empty.
if (linebuf[i] == '#')
return true; // this line was a comment.
string linecopy(linebuf);
char *token = strtok(linebuf, " \n\t");
if (!token) { // this should never happen due to checks above
char err_msg[1024];
snprintf(err_msg, 1024, "couldn't parse a token out of spec file %s " \
" on line %d", spec_file.c_str(), linenum);
throw std::runtime_error(string(err_msg));
}
string name, type = string(token);
bool constant_allowed = is_primitive(type) &&
type != string("time") &&
type != string("duration");
size_t hash_pos = linecopy.find('#');
size_t equals_pos = linecopy.find('=');
token = strtok(NULL, " \n\t=");
if (!token) {
printf("woah! on line %d of %s, there was only one token.\n",
linenum, spec_file.c_str());
printf("each line needs to have two tokens: the first is the type\n" \
"and the second is the variable name.\n");
exit(6);
}
name = string(token);
// ignore the equals sign if it's after a hash
if (equals_pos == string::npos ||
(hash_pos != string::npos && equals_pos > hash_pos)) {
// this was a variable declaration. nothing more to parse; get out of here.
vars.push_back(make_var(type, name));
return true;
}
if (!constant_allowed) {
printf("woah! constants are only allowed on primitive numeric types and "
"strings.\n");
exit(7);
}
// there is an equals sign in here, so it must be a constant declaration
string constant = linecopy.substr(equals_pos+1);
for (size_t line_terminator = constant.find_first_of("\r\n");
line_terminator != string::npos;
line_terminator = constant.find_first_of("\r\n"))
constant = constant.erase(line_terminator, 1);
// if it's not a string constant, trim the whitespace after the first token
if (type != "string") {
constant = trim_whitespace(constant, "#");
//printf("nonstring constant = [%s]\n", constant.c_str());
}
vars.push_back(new var_constant(type, name, constant, this));
return true;
}
bool msg_spec::is_integer(const std::string &type)
{
vector<string> prims;
prims.push_back("byte");
prims.push_back("char");
prims.push_back("uint8");
prims.push_back("bool");
prims.push_back("int8");
prims.push_back("uint16");
prims.push_back("int16");
prims.push_back("uint32");
prims.push_back("int32");
prims.push_back("uint64");
prims.push_back("int64");
for (vector<string>::iterator i = prims.begin(); i != prims.end(); ++i)
if (*i == type)
return true;
return false;
}
bool msg_spec::is_primitive(const string &type)
{
vector<string> prims;
prims.push_back("byte");
prims.push_back("char");
prims.push_back("uint8");
prims.push_back("bool");
prims.push_back("int8");
prims.push_back("uint16");
prims.push_back("int16");
prims.push_back("uint32");
prims.push_back("int32");
prims.push_back("uint64");
prims.push_back("int64");
prims.push_back("float32");
prims.push_back("float64");
prims.push_back("string");
prims.push_back("time");
prims.push_back("duration");
for (vector<string>::iterator i = prims.begin(); i != prims.end(); ++i)
if (*i == type)
return true;
return false;
}
bool msg_spec::is_array(const string &type)
{
if (string::npos != type.find('['))
return true;
else
return false;
}
void msg_spec::emit_cpp_includes(FILE *f)
{
assert(f);
vector<msg_spec *> sub_specs;
sub_specs = cpp_types(sub_specs);
set<string> setpkgpaths;
if (sub_specs.size() > 0) {
for (vector<msg_spec *>::iterator i = sub_specs.begin(); i != sub_specs.end(); ++i) {
string pkg_path = rospack_find((*i)->package);
if( pkg_path.size() > 0 )
setpkgpaths.insert(pkg_path + "/msg/oct/" + (*i)->package);
else {
printf("Error: could not find package %s.\n", (*i)->package.c_str());
exit(25);
}
}
}
if( setpkgpaths.size() > 0 ) {
fprintf(f, "persistent pathsadded__\n"
"if (isempty (pathsadded__))\n"
" pathsadded__ = 1;\n");
for(set<string>::iterator it = setpkgpaths.begin(); it != setpkgpaths.end(); ++it)
fprintf(f, " addpath('%s');\n", it->c_str());
fprintf(f, "end\n\n");
}
}
void msg_spec::emit_cpp_class(FILE *f, bool for_srv, const string &srv_name)
{
assert(f);
if(!g_header_done)
{
fprintf(f, "%% Auto-generated. Do not edit!\n\n");
g_header_done = true;
}
fprintf(f, "%% msg = %s_%s()\n%%\n%% %s message type, fields include:\n", g_pkg.c_str(), g_name.c_str(), g_name.c_str());
bool header_present = false;
for (vector<msg_var *>::iterator v = vars.begin(); v != vars.end(); ++v) {
fprintf(f, "%% %s\n", (*v)->oct_decl().c_str());
if ((*v)->name == "header" &&
((*v)->oct_type_name().find("Header") != string::npos))
header_present = true;
}
// skip a line so it isn't generated by help file
fprintf(f, "\n%% //! \\htmlinclude %s.msg.html\n",g_name.c_str());
fprintf(f, "function msg = %s_%s()\n", g_pkg.c_str(), g_name.c_str());
emit_cpp_includes(f);
fprintf(f, "\nmsg = [];\n");
if( for_srv && g_name == string("Request") )
fprintf(f, "msg.create_response_ = @%s_Response;\n", g_pkg.c_str());
for (vector<msg_var *>::iterator v = vars.begin(); v != vars.end(); ++v)
fprintf(f, "%s", (*v)->oct_ctor("msg").c_str());
// add the internal functions
fprintf(f, "msg.md5sum_ = @%s_%s___md5sum;\n", g_pkg.c_str(), g_name.c_str());
if (server_md5sum.length()) {
fprintf(f, "msg.server_md5sum_ = @%s_%s___server_md5sum;\n", g_pkg.c_str(), g_name.c_str());
fprintf(f, "msg.server_type_ = @%s_%s___server_type;\n", g_pkg.c_str(), g_name.c_str());
}
fprintf(f, "msg.type_ = @%s_%s___type;\n", g_pkg.c_str(), g_name.c_str());
fprintf(f, "msg.serializationLength_ = @%s_%s___serializationLength;\n", g_pkg.c_str(), g_name.c_str());
fprintf(f, "msg.serialize_ = @%s_%s___serialize;\n", g_pkg.c_str(), g_name.c_str());
fprintf(f, "msg.deserialize_ = @%s_%s___deserialize;\n", g_pkg.c_str(), g_name.c_str());
fprintf(f, "msg.message_definition_ = @%s_%s___message_definition;\n", g_pkg.c_str(), g_name.c_str());
fprintf(f, "\n");
fprintf(f, "function x = %s_%s___md5sum()\nx = '%s';\n\n", g_pkg.c_str(), g_name.c_str(), md5sum.c_str());
if (server_md5sum.length()) {
fprintf(f, "function x = %s_%s___server_md5sum()\nx = '%s';\n\n", g_pkg.c_str(), g_name.c_str(), server_md5sum.c_str());
fprintf(f, "function x = %s_%s___server_type()\nx = '%s';\n\n", g_pkg.c_str(), g_name.c_str(), service_datatype.c_str());
}
{
fprintf(f, "function x = %s_%s___message_definition()\nx = [", g_pkg.c_str(), g_name.c_str());
vector<string> definition_lines;
string_split(full_definition, definition_lines, "\n");
vector<string>::iterator it = definition_lines.begin();
vector<string>::iterator end = definition_lines.end();
for (; it != end; ++it) {
std::string& line = *it;
// Escape bare \, ', and "
size_t pos = line.find("\\");
while (pos != std::string::npos) {
line.insert(pos, "\\");
pos = line.find("\\", pos + 2);
}
pos = line.find("\"");
while (pos != std::string::npos) {
line.insert(pos, "\\");
pos = line.find("\"", pos + 2);
}
pos = line.find("'");
while (pos != std::string::npos) {
line.insert(pos, "'");
pos = line.find("'", pos + 2);
}
fprintf(f, " '%s\\n' ...\n", line.c_str());
}
fprintf(f, "];\n\n");
}
fprintf(f, "function x = %s_%s___type()\nx = '%s/%s';\n\n",
g_pkg.c_str(), g_name.c_str(), g_pkg.c_str(),
(!for_srv ? g_name.c_str() : (srv_name + g_name).c_str()));
for (vector<msg_var *>::iterator v = vars.begin(); v != vars.end(); ++v)
fprintf(f, "%s", (*v)->helper_funcs().c_str());
// serialization length
fprintf(f, "%s", serializationLength_func().c_str());
// serialize
fprintf(f, "function dat__ = %s_%s___serialize(msg__, seq__, fid__)\n", g_pkg.c_str(), g_name.c_str());
fprintf(f, "global rosoct\n\n");
fprintf(f, "c__ = 0;\n"
"file_created__ = 0;\n"
"if( ~exist('fid__','var') )\n"
" fid__ = tmpfile();\n"
" file_created__ = 1;\n"
"end\n");
if (header_present)
fputs("if (msg__.header.seq == 0)\n msg__.header.seq = seq__;\nend\n"
"if (msg__.header.stamp.sec == 0 && msg__.header.stamp.nsec == 0)\n msg__.header.stamp = rosoct_time_now();\nend\n", f);
int nExpectedCount = 0;
for (vector<msg_var *>::iterator v = vars.begin(); v != vars.end(); ++v)
fputs((*v)->serialization_code("msg__", nExpectedCount).c_str(), f);
if( nExpectedCount > 0 ) {
fprintf(f,"if( c__ ~= %d )\n"
" error('some members of msg %s:%s are initialized incorrectly!');\n"
"end\n", nExpectedCount, g_pkg.c_str(), g_name.c_str());
}
fprintf(f,"if( file_created__ )\n"
" fseek(fid__,0,SEEK_SET);\n"
" dat__ = fread(fid__,Inf,'uint8=>uint8');\n"
" fclose(fid__);\n"
"end\n\n");
// deserialize
fprintf(f, "function msg__ = %s_%s___deserialize(dat__, fid__)\n", g_pkg.c_str(), g_name.c_str());
fprintf(f, "msg__ = %s_%s();\n", g_pkg.c_str(), g_name.c_str());
fprintf(f, "file_created__ = 0;\n"
"if( ~exist('fid__','var') )\n"
" fid__ = tmpfile();\n"
" file_created__ = 1;\n"
" fwrite(fid__,dat__,'uint8');\n"
" fseek(fid__,0,SEEK_SET);\n"
"end\n");
for (vector<msg_var *>::iterator v = vars.begin(); v != vars.end(); ++v)
fputs((*v)->deserialization_code("msg__").c_str(), f);
fprintf(f, "if( file_created__ )\n"
" fclose(fid__);\n"
"end\n");
// extra
fprintf(f, "function l__ = %s_%s___sum_array_length__(x)\n"
"if( ~exist('x','var') || isempty(x) )\n"
" l__ = 0;\n"
"else\n"
" l__ = sum(x(:));\n"
"end\n\n", g_pkg.c_str(), g_name.c_str());
// if (!for_srv)
// fputs("\n}\n\n", f);
}
string msg_spec::serializationLength_func()
{
stringstream ss;
ss << "function l__ = " << g_pkg << "_" << g_name << "___serializationLength(msg)" << endl;
if( vars.size() > 0 )
ss << "l__ = ";
else
ss << "l__ = 0";
for (vector<msg_var *>::iterator v = vars.begin(); v != vars.end(); ++v)
ss << " ..." << endl << " + " << (*v)->length_expr("msg");
ss << ";" << endl << endl;
return ss.str();
}
string msg_spec::to_list_func() { return string(""); }
bool msg_spec::is_fixed_length()
{
for (vector<msg_var *>::iterator v = vars.begin(); v != vars.end(); ++v)
if (!(*v)->is_fixed_length())
return false;
return true;
}
vector<msg_spec *> msg_spec::cpp_types(vector<msg_spec *> types)
{
for (vector<msg_var *>::iterator v = vars.begin(); v != vars.end(); ++v)
types = (*v)->oct_types(types);
return types;
}
string msg_spec::equals(const string &prefix, int indent)
{
return "";
}
msg_var *msg_spec::make_var(const string &type, const string &name)
{
if (msg_spec::is_primitive(type))
return new var_primitive(type, name, this);
else if (msg_spec::is_array(type))
return new var_array(type, name, this);
else
return new var_complex(type, name, this);
}