00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 import sys
00040 import os
00041 import traceback
00042
00043 import roslib.msgs
00044 import roslib.packages
00045 import roslib.gentools
00046 from rospkg import RosPack
00047
00048 try:
00049 from cStringIO import StringIO
00050 except ImportError:
00051 from io import StringIO
00052
00053 MSG_TYPE_TO_CPP = {'byte': 'int8_t', 'char': 'uint8_t',
00054 'bool': 'uint8_t',
00055 'uint8': 'uint8_t', 'int8': 'int8_t',
00056 'uint16': 'uint16_t', 'int16': 'int16_t',
00057 'uint32': 'uint32_t', 'int32': 'int32_t',
00058 'uint64': 'uint64_t', 'int64': 'int64_t',
00059 'float32': 'float',
00060 'float64': 'double',
00061 'string': 'std::basic_string<char, std::char_traits<char>, typename ContainerAllocator::template rebind<char>::other > ',
00062 'time': 'ros::Time',
00063 'duration': 'ros::Duration'}
00064
00065 def msg_type_to_cpp(type):
00066 """
00067 Converts a message type (e.g. uint32, std_msgs/String, etc.) into the C++ declaration
00068 for that type (e.g. uint32_t, std_msgs::String_<ContainerAllocator>)
00069
00070 @param type: The message type
00071 @type type: str
00072 @return: The C++ declaration
00073 @rtype: str
00074 """
00075 (base_type, is_array, array_len) = roslib.msgs.parse_type(type)
00076 cpp_type = None
00077 if (roslib.msgs.is_builtin(base_type)):
00078 cpp_type = MSG_TYPE_TO_CPP[base_type]
00079 elif (len(base_type.split('/')) == 1):
00080 if (roslib.msgs.is_header_type(base_type)):
00081 cpp_type = ' ::std_msgs::Header_<ContainerAllocator> '
00082 else:
00083 cpp_type = '%s_<ContainerAllocator> '%(base_type)
00084 else:
00085 pkg = base_type.split('/')[0]
00086 msg = base_type.split('/')[1]
00087 cpp_type = ' ::%s::%s_<ContainerAllocator> '%(pkg, msg)
00088
00089 if (is_array):
00090 if (array_len is None):
00091 return 'std::vector<%s, typename ContainerAllocator::template rebind<%s>::other > '%(cpp_type, cpp_type)
00092 else:
00093 return 'boost::array<%s, %s> '%(cpp_type, array_len)
00094 else:
00095 return cpp_type
00096
00097 def cpp_message_declarations(name_prefix, msg):
00098 """
00099 Returns the different possible C++ declarations for a message given the message itself.
00100
00101 @param name_prefix: The C++ prefix to be prepended to the name, e.g. "std_msgs::"
00102 @type name_prefix: str
00103 @param msg: The message type
00104 @type msg: str
00105 @return: A tuple of 3 different names. cpp_message_decelarations("std_msgs::", "String") returns the tuple
00106 ("std_msgs::String_", "std_msgs::String_<ContainerAllocator>", "std_msgs::String")
00107 @rtype: str
00108 """
00109 pkg, basetype = roslib.names.package_resource_name(msg)
00110 cpp_name = ' ::%s%s'%(name_prefix, msg)
00111 if (pkg):
00112 cpp_name = ' ::%s::%s'%(pkg, basetype)
00113 return ('%s_'%(cpp_name), '%s_<ContainerAllocator> '%(cpp_name), '%s'%(cpp_name))
00114
00115 def write_begin(s, spec, file):
00116 """
00117 Writes the beginning of the header file: a comment saying it's auto-generated and the include guards
00118
00119 @param s: The stream to write to
00120 @type s: stream
00121 @param spec: The spec
00122 @type spec: roslib.msgs.MsgSpec
00123 @param file: The file this message is being generated for
00124 @type file: str
00125 """
00126 s.write("/* Auto-generated by genmsg_cpp for file %s */\n"%(file))
00127 s.write('#ifndef %s_MESSAGE_%s_H\n'%(spec.package.upper(), spec.short_name.upper()))
00128 s.write('#define %s_MESSAGE_%s_H\n'%(spec.package.upper(), spec.short_name.upper()))
00129
00130 def write_end(s, spec):
00131 """
00132 Writes the end of the header file: the ending of the include guards
00133
00134 @param s: The stream to write to
00135 @type s: stream
00136 @param spec: The spec
00137 @type spec: roslib.msgs.MsgSpec
00138 """
00139 s.write('#endif // %s_MESSAGE_%s_H\n'%(spec.package.upper(), spec.short_name.upper()))
00140
00141 def write_generic_includes(s):
00142 """
00143 Writes the includes that all messages need
00144
00145 @param s: The stream to write to
00146 @type s: stream
00147 """
00148 s.write('#include <string>\n')
00149 s.write('#include <vector>\n')
00150 s.write('#include <map>\n')
00151 s.write('#include <ostream>\n')
00152 s.write('#include "ros/serialization.h"\n')
00153 s.write('#include "ros/builtin_message_traits.h"\n')
00154 s.write('#include "ros/message_operations.h"\n')
00155 s.write('#include "ros/time.h"\n\n')
00156 s.write('#include "ros/macros.h"\n\n')
00157 s.write('#include "ros/assert.h"\n\n')
00158
00159 def write_includes(s, spec):
00160 """
00161 Writes the message-specific includes
00162
00163 @param s: The stream to write to
00164 @type s: stream
00165 @param spec: The message spec to iterate over
00166 @type spec: roslib.msgs.MsgSpec
00167 """
00168 for field in spec.parsed_fields():
00169 if (not field.is_builtin):
00170 if (field.is_header):
00171 s.write('#include "std_msgs/Header.h"\n')
00172 else:
00173 (pkg, name) = roslib.names.package_resource_name(field.base_type)
00174 pkg = pkg or spec.package
00175 s.write('#include "%s/%s.h"\n'%(pkg, name))
00176
00177 s.write('\n')
00178
00179
00180 def write_struct(s, spec, cpp_name_prefix, extra_deprecated_traits = {}):
00181 """
00182 Writes the entire message struct: declaration, constructors, members, constants and (deprecated) member functions
00183 @param s: The stream to write to
00184 @type s: stream
00185 @param spec: The message spec
00186 @type spec: roslib.msgs.MsgSpec
00187 @param cpp_name_prefix: The C++ prefix to use when referring to the message, e.g. "std_msgs::"
00188 @type cpp_name_prefix: str
00189 """
00190
00191 msg = spec.short_name
00192 s.write('template <class ContainerAllocator>\n')
00193 s.write('struct %s_ {\n'%(msg))
00194 s.write(' typedef %s_<ContainerAllocator> Type;\n\n'%(msg))
00195
00196 write_constructors(s, spec, cpp_name_prefix)
00197 write_members(s, spec)
00198 write_constant_declarations(s, spec)
00199
00200
00201
00202
00203
00204
00205
00206
00207 (cpp_msg_unqualified, cpp_msg_with_alloc, cpp_msg_base) = cpp_message_declarations(cpp_name_prefix, msg)
00208 s.write(' typedef boost::shared_ptr<%s> Ptr;\n'%(cpp_msg_with_alloc))
00209 s.write(' typedef boost::shared_ptr<%s const> ConstPtr;\n'%(cpp_msg_with_alloc))
00210 s.write(' boost::shared_ptr<std::map<std::string, std::string> > __connection_header;\n')
00211
00212 s.write('}; // struct %s\n'%(msg))
00213
00214 s.write('typedef %s_<std::allocator<void> > %s;\n\n'%(cpp_msg_base, msg))
00215 s.write('typedef boost::shared_ptr<%s> %sPtr;\n'%(cpp_msg_base, msg))
00216 s.write('typedef boost::shared_ptr<%s const> %sConstPtr;\n\n'%(cpp_msg_base, msg))
00217
00218 def default_value(type):
00219 """
00220 Returns the value to initialize a message member with. 0 for integer types, 0.0 for floating point, false for bool,
00221 empty string for everything else
00222
00223 @param type: The type
00224 @type type: str
00225 """
00226 if type in ['byte', 'int8', 'int16', 'int32', 'int64',
00227 'char', 'uint8', 'uint16', 'uint32', 'uint64']:
00228 return '0'
00229 elif type in ['float32', 'float64']:
00230 return '0.0'
00231 elif type == 'bool':
00232 return 'false'
00233
00234 return ""
00235
00236 def takes_allocator(type):
00237 """
00238 Returns whether or not a type can take an allocator in its constructor. False for all builtin types except string.
00239 True for all others.
00240
00241 @param type: The type
00242 @type: str
00243 """
00244 return not type in ['byte', 'int8', 'int16', 'int32', 'int64',
00245 'char', 'uint8', 'uint16', 'uint32', 'uint64',
00246 'float32', 'float64', 'bool', 'time', 'duration']
00247
00248 def write_initializer_list(s, spec, container_gets_allocator):
00249 """
00250 Writes the initializer list for a constructor
00251
00252 @param s: The stream to write to
00253 @type s: stream
00254 @param spec: The message spec
00255 @type spec: roslib.msgs.MsgSpec
00256 @param container_gets_allocator: Whether or not a container type (whether it's another message, a vector, array or string)
00257 should have the allocator passed to its constructor. Assumes the allocator is named _alloc.
00258 @type container_gets_allocator: bool
00259 """
00260
00261 i = 0
00262 for field in spec.parsed_fields():
00263 if (i == 0):
00264 s.write(' : ')
00265 else:
00266 s.write(' , ')
00267
00268 val = default_value(field.base_type)
00269 use_alloc = takes_allocator(field.base_type)
00270 if (field.is_array):
00271 if (field.array_len is None and container_gets_allocator):
00272 s.write('%s(_alloc)\n'%(field.name))
00273 else:
00274 s.write('%s()\n'%(field.name))
00275 else:
00276 if (container_gets_allocator and use_alloc):
00277 s.write('%s(_alloc)\n'%(field.name))
00278 else:
00279 s.write('%s(%s)\n'%(field.name, val))
00280 i = i + 1
00281
00282 def write_fixed_length_assigns(s, spec, container_gets_allocator, cpp_name_prefix):
00283 """
00284 Initialize any fixed-length arrays
00285
00286 @param s: The stream to write to
00287 @type s: stream
00288 @param spec: The message spec
00289 @type spec: roslib.msgs.MsgSpec
00290 @param container_gets_allocator: Whether or not a container type (whether it's another message, a vector, array or string)
00291 should have the allocator passed to its constructor. Assumes the allocator is named _alloc.
00292 @type container_gets_allocator: bool
00293 @param cpp_name_prefix: The C++ prefix to use when referring to the message, e.g. "std_msgs::"
00294 @type cpp_name_prefix: str
00295 """
00296
00297 for field in spec.parsed_fields():
00298 if (not field.is_array or field.array_len is None):
00299 continue
00300
00301 val = default_value(field.base_type)
00302 if (container_gets_allocator and takes_allocator(field.base_type)):
00303
00304 if (field.base_type == "string"):
00305 string_cpp = msg_type_to_cpp("string")
00306 s.write(' %s.assign(%s(_alloc));\n'%(field.name, string_cpp))
00307 else:
00308 (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, field.base_type)
00309 s.write(' %s.assign(%s(_alloc));\n'%(field.name, cpp_msg_with_alloc))
00310 elif (len(val) > 0):
00311 s.write(' %s.assign(%s);\n'%(field.name, val))
00312
00313 def write_constructors(s, spec, cpp_name_prefix):
00314 """
00315 Writes any necessary constructors for the message
00316
00317 @param s: The stream to write to
00318 @type s: stream
00319 @param spec: The message spec
00320 @type spec: roslib.msgs.MsgSpec
00321 @param cpp_name_prefix: The C++ prefix to use when referring to the message, e.g. "std_msgs::"
00322 @type cpp_name_prefix: str
00323 """
00324
00325 msg = spec.short_name
00326
00327
00328 s.write(' %s_()\n'%(msg))
00329 write_initializer_list(s, spec, False)
00330 s.write(' {\n')
00331 write_fixed_length_assigns(s, spec, False, cpp_name_prefix)
00332 s.write(' }\n\n')
00333
00334
00335 s.write(' %s_(const ContainerAllocator& _alloc)\n'%(msg))
00336 write_initializer_list(s, spec, True)
00337 s.write(' {\n')
00338 write_fixed_length_assigns(s, spec, True, cpp_name_prefix)
00339 s.write(' }\n\n')
00340
00341 def write_member(s, field):
00342 """
00343 Writes a single member's declaration and type typedef
00344
00345 @param s: The stream to write to
00346 @type s: stream
00347 @param type: The member type
00348 @type type: str
00349 @param name: The name of the member
00350 @type name: str
00351 """
00352 cpp_type = msg_type_to_cpp(field.type)
00353 s.write(' typedef %s _%s_type;\n'%(cpp_type, field.name))
00354 s.write(' %s %s;\n\n'%(cpp_type, field.name))
00355
00356 def write_members(s, spec):
00357 """
00358 Write all the member declarations
00359
00360 @param s: The stream to write to
00361 @type s: stream
00362 @param spec: The message spec
00363 @type spec: roslib.msgs.MsgSpec
00364 """
00365 [write_member(s, field) for field in spec.parsed_fields()]
00366
00367 def escape_string(str):
00368 str = str.replace('\\', '\\\\')
00369 str = str.replace('"', '\\"')
00370 return str
00371
00372 def write_constant_declaration(s, constant):
00373 """
00374 Write a constant value as a static member
00375
00376 @param s: The stream to write to
00377 @type s: stream
00378 @param constant: The constant
00379 @type constant: roslib.msgs.Constant
00380 """
00381
00382
00383 if (constant.type in ['byte', 'int8', 'int16', 'int32', 'int64', 'char', 'uint8', 'uint16', 'uint32', 'uint64']):
00384 s.write(' enum { %s = %s };\n'%(constant.name, constant.val))
00385 else:
00386 s.write(' static const %s %s;\n'%(msg_type_to_cpp(constant.type), constant.name))
00387
00388 def write_constant_declarations(s, spec):
00389 """
00390 Write all the constants from a spec as static members
00391
00392 @param s: The stream to write to
00393 @type s: stream
00394 @param spec: The message spec
00395 @type spec: roslib.msgs.MsgSpec
00396 """
00397 [write_constant_declaration(s, constant) for constant in spec.constants]
00398 s.write('\n')
00399
00400 def write_constant_definition(s, spec, constant):
00401 """
00402 Write a constant value as a static member
00403
00404 @param s: The stream to write to
00405 @type s: stream
00406 @param constant: The constant
00407 @type constant: roslib.msgs.Constant
00408 """
00409
00410
00411 if (constant.type not in ['byte', 'int8', 'int16', 'int32', 'int64', 'char', 'uint8', 'uint16', 'uint32', 'uint64', 'string']):
00412 s.write('template<typename ContainerAllocator> const %s %s_<ContainerAllocator>::%s = %s;\n'%(msg_type_to_cpp(constant.type), spec.short_name, constant.name, constant.val))
00413 elif (constant.type == 'string'):
00414 s.write('template<typename ContainerAllocator> const %s %s_<ContainerAllocator>::%s = "%s";\n'%(msg_type_to_cpp(constant.type), spec.short_name, constant.name, escape_string(constant.val)))
00415
00416 def write_constant_definitions(s, spec):
00417 """
00418 Write all the constants from a spec as static members
00419
00420 @param s: The stream to write to
00421 @type s: stream
00422 @param spec: The message spec
00423 @type spec: roslib.msgs.MsgSpec
00424 """
00425 [write_constant_definition(s, spec, constant) for constant in spec.constants]
00426 s.write('\n')
00427
00428 def is_fixed_length(spec):
00429 """
00430 Returns whether or not the message is fixed-length
00431
00432 @param spec: The message spec
00433 @type spec: roslib.msgs.MsgSpec
00434 @param package: The package of the
00435 @type package: str
00436 """
00437 types = []
00438 for field in spec.parsed_fields():
00439 if (field.is_array and field.array_len is None):
00440 return False
00441
00442 if (field.base_type == 'string'):
00443 return False
00444
00445 if (not field.is_builtin):
00446 types.append(field.base_type)
00447
00448 types = set(types)
00449 for type in types:
00450 type = roslib.msgs.resolve_type(type, spec.package)
00451 (_, new_spec) = roslib.msgs.load_by_type(type, spec.package)
00452 if (not is_fixed_length(new_spec)):
00453 return False
00454
00455 return True
00456
00457 def write_deprecated_member_functions(s, spec, traits):
00458 """
00459 Writes the deprecated member functions for backwards compatibility
00460 """
00461 for field in spec.parsed_fields():
00462 if (field.is_array):
00463 s.write(' ROS_DEPRECATED uint32_t get_%s_size() const { return (uint32_t)%s.size(); }\n'%(field.name, field.name))
00464
00465 if (field.array_len is None):
00466 s.write(' ROS_DEPRECATED void set_%s_size(uint32_t size) { %s.resize((size_t)size); }\n'%(field.name, field.name))
00467 s.write(' ROS_DEPRECATED void get_%s_vec(%s& vec) const { vec = this->%s; }\n'%(field.name, msg_type_to_cpp(field.type), field.name))
00468 s.write(' ROS_DEPRECATED void set_%s_vec(const %s& vec) { this->%s = vec; }\n'%(field.name, msg_type_to_cpp(field.type), field.name))
00469
00470 for k, v in traits.items():
00471 s.write('private:\n')
00472 s.write(' static const char* __s_get%s_() { return "%s"; }\n'%(k, v))
00473 s.write('public:\n')
00474 s.write(' ROS_DEPRECATED static const std::string __s_get%s() { return __s_get%s_(); }\n\n'%(k, k))
00475 s.write(' ROS_DEPRECATED const std::string __get%s() const { return __s_get%s_(); }\n\n'%(k, k))
00476
00477 s.write(' ROS_DEPRECATED virtual uint8_t *serialize(uint8_t *write_ptr, uint32_t seq) const\n {\n')
00478 s.write(' ros::serialization::OStream stream(write_ptr, 1000000000);\n')
00479 for field in spec.parsed_fields():
00480 s.write(' ros::serialization::serialize(stream, %s);\n'%(field.name))
00481 s.write(' return stream.getData();\n }\n\n')
00482
00483 s.write(' ROS_DEPRECATED virtual uint8_t *deserialize(uint8_t *read_ptr)\n {\n')
00484 s.write(' ros::serialization::IStream stream(read_ptr, 1000000000);\n');
00485 for field in spec.parsed_fields():
00486 s.write(' ros::serialization::deserialize(stream, %s);\n'%(field.name))
00487 s.write(' return stream.getData();\n }\n\n')
00488
00489 s.write(' ROS_DEPRECATED virtual uint32_t serializationLength() const\n {\n')
00490 s.write(' uint32_t size = 0;\n');
00491 for field in spec.parsed_fields():
00492 s.write(' size += ros::serialization::serializationLength(%s);\n'%(field.name))
00493 s.write(' return size;\n }\n\n')
00494
00495 def compute_full_text_escaped(gen_deps_dict):
00496 """
00497 Same as roslib.gentools.compute_full_text, except that the
00498 resulting text is escaped to be safe for C++ double quotes
00499
00500 @param get_deps_dict: dictionary returned by get_dependencies call
00501 @type get_deps_dict: dict
00502 @return: concatenated text for msg/srv file and embedded msg/srv types. Text will be escaped for double quotes
00503 @rtype: str
00504 """
00505 definition = roslib.gentools.compute_full_text(gen_deps_dict)
00506 lines = definition.split('\n')
00507 s = StringIO()
00508 for line in lines:
00509 line = escape_string(line)
00510 s.write('%s\\n\\\n'%(line))
00511
00512 val = s.getvalue()
00513 s.close()
00514 return val
00515
00516 def is_hex_string(str):
00517 for c in str:
00518 if c not in '0123456789abcdefABCDEF':
00519 return False
00520
00521 return True
00522
00523 def write_trait_char_class(s, class_name, cpp_msg_with_alloc, value, write_static_hex_value = False):
00524 """
00525 Writes a class trait for traits which have static value() members that return const char*
00526
00527 e.g. write_trait_char_class(s, "MD5Sum", "std_msgs::String_<ContainerAllocator>", "hello") yields:
00528 template<class ContainerAllocator>
00529 struct MD5Sum<std_msgs::String_<ContainerAllocator> >
00530 {
00531 static const char* value() { return "hello"; }
00532 static const char* value(const std_msgs::String_<ContainerAllocator>&) { return value(); }
00533 };
00534
00535 @param s: The stream to write to
00536 @type s: stream
00537 @param class_name: The name of the trait class to write
00538 @type class_name: str
00539 @param cpp_msg_with_alloc: The C++ declaration of the message, including the allocator template
00540 @type cpp_msg_with_alloc: str
00541 @param value: The value to return in the string
00542 @type value: str
00543 @param write_static_hex_value: Whether or not to write a set of compile-time-checkable static values. Useful for,
00544 for example, MD5Sum. Writes static const uint64_t static_value1... static_valueN
00545 @type write_static_hex_value: bool
00546 @raise ValueError if write_static_hex_value is True but value contains characters invalid in a hex value
00547 """
00548 s.write('template<class ContainerAllocator>\nstruct %s<%s> {\n'%(class_name, cpp_msg_with_alloc))
00549 s.write(' static const char* value() \n {\n return "%s";\n }\n\n'%(value))
00550 s.write(' static const char* value(const %s&) { return value(); } \n'%(cpp_msg_with_alloc))
00551 if (write_static_hex_value):
00552 if (not is_hex_string(value)):
00553 raise ValueError('%s is not a hex value'%(value))
00554
00555 iter_count = len(value) / 16
00556 for i in range(0, int(iter_count)):
00557 start = i*16
00558 s.write(' static const uint64_t static_value%s = 0x%sULL;\n'%((i+1), value[start:start+16]))
00559 s.write('};\n\n')
00560
00561 def write_trait_true_class(s, class_name, cpp_msg_with_alloc):
00562 """
00563 Writes a true/false trait class
00564
00565 @param s: stream to write to
00566 @type s: stream
00567 @param class_name: Name of the trait class
00568 @type class_name: str
00569 @param cpp_msg_with_alloc: The C++ declaration of the message, including the allocator template
00570 @type cpp_msg_with_alloc: str
00571 """
00572 s.write('template<class ContainerAllocator> struct %s<%s> : public TrueType {};\n'%(class_name, cpp_msg_with_alloc))
00573
00574 def write_traits(s, spec, cpp_name_prefix, datatype = None, rospack=None):
00575 """
00576 Writes all the traits classes for a message
00577
00578 @param s: The stream to write to
00579 @type s: stream
00580 @param spec: The message spec
00581 @type spec: roslib.msgs.MsgSpec
00582 @param cpp_name_prefix: The C++ prefix to prepend to a message to refer to it (e.g. "std_msgs::")
00583 @type cpp_name_prefix: str
00584 @param datatype: The string to write as the datatype of the message. If None (default), pkg/msg is used.
00585 @type datatype: str
00586 """
00587
00588 gendeps_dict = roslib.gentools.get_dependencies(spec, spec.package, compute_files=False, rospack=rospack)
00589 md5sum = roslib.gentools.compute_md5(gendeps_dict, rospack=rospack)
00590 full_text = compute_full_text_escaped(gendeps_dict)
00591
00592 if (datatype is None):
00593 datatype = '%s'%(spec.full_name)
00594
00595 (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, spec.short_name)
00596 s.write('namespace ros\n{\n')
00597 s.write('namespace message_traits\n{\n')
00598
00599 write_trait_true_class(s, 'IsMessage', cpp_msg_with_alloc)
00600 write_trait_true_class(s, 'IsMessage', cpp_msg_with_alloc + " const")
00601
00602 write_trait_char_class(s, 'MD5Sum', cpp_msg_with_alloc, md5sum, True)
00603 write_trait_char_class(s, 'DataType', cpp_msg_with_alloc, datatype)
00604 write_trait_char_class(s, 'Definition', cpp_msg_with_alloc, full_text)
00605
00606 if (spec.has_header()):
00607 write_trait_true_class(s, 'HasHeader', cpp_msg_with_alloc)
00608 write_trait_true_class(s, 'HasHeader', ' const' + cpp_msg_with_alloc)
00609
00610 if (is_fixed_length(spec)):
00611 write_trait_true_class(s, 'IsFixedSize', cpp_msg_with_alloc)
00612
00613 s.write('} // namespace message_traits\n')
00614 s.write('} // namespace ros\n\n')
00615
00616 def write_operations(s, spec, cpp_name_prefix):
00617 (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, spec.short_name)
00618 s.write('namespace ros\n{\n')
00619 s.write('namespace message_operations\n{\n')
00620
00621
00622 s.write('\ntemplate<class ContainerAllocator>\nstruct Printer<%s>\n{\n'%(cpp_msg_with_alloc))
00623 s.write(' template<typename Stream> static void stream(Stream& s, const std::string& indent, const %s& v) \n {\n'%cpp_msg_with_alloc)
00624 for field in spec.parsed_fields():
00625 cpp_type = msg_type_to_cpp(field.base_type)
00626 if (field.is_array):
00627 s.write(' s << indent << "%s[]" << std::endl;\n'%(field.name))
00628 s.write(' for (size_t i = 0; i < v.%s.size(); ++i)\n {\n'%(field.name))
00629 s.write(' s << indent << " %s[" << i << "]: ";\n'%field.name)
00630 indent_increment = ' '
00631 if (not field.is_builtin):
00632 s.write(' s << std::endl;\n')
00633 s.write(' s << indent;\n')
00634 indent_increment = ' ';
00635 s.write(' Printer<%s>::stream(s, indent + "%s", v.%s[i]);\n'%(cpp_type, indent_increment, field.name))
00636 s.write(' }\n')
00637 else:
00638 s.write(' s << indent << "%s: ";\n'%field.name)
00639 indent_increment = ' '
00640 if (not field.is_builtin or field.is_array):
00641 s.write('s << std::endl;\n')
00642 s.write(' Printer<%s>::stream(s, indent + "%s", v.%s);\n'%(cpp_type, indent_increment, field.name))
00643 s.write(' }\n')
00644 s.write('};\n\n')
00645
00646 s.write('\n')
00647
00648 s.write('} // namespace message_operations\n')
00649 s.write('} // namespace ros\n\n')
00650
00651 def write_serialization(s, spec, cpp_name_prefix):
00652 """
00653 Writes the Serializer class for a message
00654
00655 @param s: Stream to write to
00656 @type s: stream
00657 @param spec: The message spec
00658 @type spec: roslib.msgs.MsgSpec
00659 @param cpp_name_prefix: The C++ prefix to prepend to a message to refer to it (e.g. "std_msgs::")
00660 @type cpp_name_prefix: str
00661 """
00662 (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, spec.short_name)
00663
00664 s.write('namespace ros\n{\n')
00665 s.write('namespace serialization\n{\n\n')
00666
00667 s.write('template<class ContainerAllocator> struct Serializer<%s>\n{\n'%(cpp_msg_with_alloc))
00668
00669 s.write(' template<typename Stream, typename T> inline static void allInOne(Stream& stream, T m)\n {\n')
00670 for field in spec.parsed_fields():
00671 s.write(' stream.next(m.%s);\n'%(field.name))
00672 s.write(' }\n\n')
00673
00674 s.write(' ROS_DECLARE_ALLINONE_SERIALIZER;\n')
00675
00676 s.write('}; // struct %s_\n'%(spec.short_name))
00677
00678 s.write('} // namespace serialization\n')
00679 s.write('} // namespace ros\n\n')
00680
00681 def write_ostream_operator(s, spec, cpp_name_prefix):
00682 (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, spec.short_name)
00683 s.write('template<typename ContainerAllocator>\nstd::ostream& operator<<(std::ostream& s, const %s& v)\n{\n'%(cpp_msg_with_alloc))
00684 s.write(' ros::message_operations::Printer<%s>::stream(s, "", v);\n return s;}\n\n'%(cpp_msg_with_alloc))
00685
00686 def generate(msg_path):
00687 """
00688 Generate a message
00689
00690 @param msg_path: The path to the .msg file
00691 @type msg_path: str
00692 """
00693 (package_dir, package) = roslib.packages.get_dir_pkg(msg_path)
00694 (_, spec) = roslib.msgs.load_from_file(msg_path, package)
00695
00696 s = StringIO()
00697 write_begin(s, spec, msg_path)
00698 write_generic_includes(s)
00699 write_includes(s, spec)
00700
00701 cpp_prefix = '%s::'%(package)
00702
00703 s.write('namespace %s\n{\n'%(package))
00704 write_struct(s, spec, cpp_prefix)
00705 write_constant_definitions(s, spec)
00706 write_ostream_operator(s, spec, cpp_prefix)
00707 s.write('} // namespace %s\n\n'%(package))
00708
00709 rospack = RosPack()
00710 write_traits(s, spec, cpp_prefix, rospack=rospack)
00711 write_serialization(s, spec, cpp_prefix)
00712 write_operations(s, spec, cpp_prefix)
00713
00714
00715
00716
00717 if (package == "std_msgs" and spec.short_name == "Header"):
00718 s.write("#define STD_MSGS_INCLUDING_HEADER_DEPRECATED_DEF 1\n")
00719 s.write("#include <std_msgs/header_deprecated_def.h>\n")
00720 s.write("#undef STD_MSGS_INCLUDING_HEADER_DEPRECATED_DEF\n\n")
00721
00722 write_end(s, spec)
00723
00724 output_dir = '%s/msg_gen/cpp/include/%s'%(package_dir, package)
00725 if (not os.path.exists(output_dir)):
00726
00727
00728 try:
00729 os.makedirs(output_dir)
00730 except OSError as e:
00731 pass
00732
00733 f = open('%s/%s.h'%(output_dir, spec.short_name), 'w')
00734 f.write(s.getvalue() + "\n")
00735
00736 s.close()
00737
00738 def generate_messages(argv):
00739 for arg in argv[1:]:
00740 generate(arg)
00741
00742 if __name__ == "__main__":
00743 roslib.msgs.set_verbose(False)
00744 generate_messages(sys.argv)
00745