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
00211 s.write('}; // struct %s\n'%(msg))
00212
00213 s.write('typedef %s_<std::allocator<void> > %s;\n\n'%(cpp_msg_base, msg))
00214 s.write('typedef boost::shared_ptr<%s> %sPtr;\n'%(cpp_msg_base, msg))
00215 s.write('typedef boost::shared_ptr<%s const> %sConstPtr;\n\n'%(cpp_msg_base, msg))
00216
00217 def default_value(type):
00218 """
00219 Returns the value to initialize a message member with. 0 for integer types, 0.0 for floating point, false for bool,
00220 empty string for everything else
00221
00222 @param type: The type
00223 @type type: str
00224 """
00225 if type in ['byte', 'int8', 'int16', 'int32', 'int64',
00226 'char', 'uint8', 'uint16', 'uint32', 'uint64']:
00227 return '0'
00228 elif type in ['float32', 'float64']:
00229 return '0.0'
00230 elif type == 'bool':
00231 return 'false'
00232
00233 return ""
00234
00235 def takes_allocator(type):
00236 """
00237 Returns whether or not a type can take an allocator in its constructor. False for all builtin types except string.
00238 True for all others.
00239
00240 @param type: The type
00241 @type: str
00242 """
00243 return not type in ['byte', 'int8', 'int16', 'int32', 'int64',
00244 'char', 'uint8', 'uint16', 'uint32', 'uint64',
00245 'float32', 'float64', 'bool', 'time', 'duration']
00246
00247 def write_initializer_list(s, spec, container_gets_allocator):
00248 """
00249 Writes the initializer list for a constructor
00250
00251 @param s: The stream to write to
00252 @type s: stream
00253 @param spec: The message spec
00254 @type spec: roslib.msgs.MsgSpec
00255 @param container_gets_allocator: Whether or not a container type (whether it's another message, a vector, array or string)
00256 should have the allocator passed to its constructor. Assumes the allocator is named _alloc.
00257 @type container_gets_allocator: bool
00258 """
00259
00260 i = 0
00261 for field in spec.parsed_fields():
00262 if (i == 0):
00263 s.write(' : ')
00264 else:
00265 s.write(' , ')
00266
00267 val = default_value(field.base_type)
00268 use_alloc = takes_allocator(field.base_type)
00269 if (field.is_array):
00270 if (field.array_len is None and container_gets_allocator):
00271 s.write('%s(_alloc)\n'%(field.name))
00272 else:
00273 s.write('%s()\n'%(field.name))
00274 else:
00275 if (container_gets_allocator and use_alloc):
00276 s.write('%s(_alloc)\n'%(field.name))
00277 else:
00278 s.write('%s(%s)\n'%(field.name, val))
00279 i = i + 1
00280
00281 def write_fixed_length_assigns(s, spec, container_gets_allocator, cpp_name_prefix):
00282 """
00283 Initialize any fixed-length arrays
00284
00285 @param s: The stream to write to
00286 @type s: stream
00287 @param spec: The message spec
00288 @type spec: roslib.msgs.MsgSpec
00289 @param container_gets_allocator: Whether or not a container type (whether it's another message, a vector, array or string)
00290 should have the allocator passed to its constructor. Assumes the allocator is named _alloc.
00291 @type container_gets_allocator: bool
00292 @param cpp_name_prefix: The C++ prefix to use when referring to the message, e.g. "std_msgs::"
00293 @type cpp_name_prefix: str
00294 """
00295
00296 for field in spec.parsed_fields():
00297 if (not field.is_array or field.array_len is None):
00298 continue
00299
00300 val = default_value(field.base_type)
00301 if (container_gets_allocator and takes_allocator(field.base_type)):
00302
00303 if (field.base_type == "string"):
00304 string_cpp = msg_type_to_cpp("string")
00305 s.write(' %s.assign(%s(_alloc));\n'%(field.name, string_cpp))
00306 else:
00307 (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, field.base_type)
00308 s.write(' %s.assign(%s(_alloc));\n'%(field.name, cpp_msg_with_alloc))
00309 elif (len(val) > 0):
00310 s.write(' %s.assign(%s);\n'%(field.name, val))
00311
00312 def write_constructors(s, spec, cpp_name_prefix):
00313 """
00314 Writes any necessary constructors for the message
00315
00316 @param s: The stream to write to
00317 @type s: stream
00318 @param spec: The message spec
00319 @type spec: roslib.msgs.MsgSpec
00320 @param cpp_name_prefix: The C++ prefix to use when referring to the message, e.g. "std_msgs::"
00321 @type cpp_name_prefix: str
00322 """
00323
00324 msg = spec.short_name
00325
00326
00327 s.write(' %s_()\n'%(msg))
00328 write_initializer_list(s, spec, False)
00329 s.write(' {\n')
00330 write_fixed_length_assigns(s, spec, False, cpp_name_prefix)
00331 s.write(' }\n\n')
00332
00333
00334 s.write(' %s_(const ContainerAllocator& _alloc)\n'%(msg))
00335 write_initializer_list(s, spec, True)
00336 s.write(' {\n')
00337 write_fixed_length_assigns(s, spec, True, cpp_name_prefix)
00338 s.write(' }\n\n')
00339
00340 def write_member(s, field):
00341 """
00342 Writes a single member's declaration and type typedef
00343
00344 @param s: The stream to write to
00345 @type s: stream
00346 @param type: The member type
00347 @type type: str
00348 @param name: The name of the member
00349 @type name: str
00350 """
00351 cpp_type = msg_type_to_cpp(field.type)
00352 s.write(' typedef %s _%s_type;\n'%(cpp_type, field.name))
00353 s.write(' %s %s;\n\n'%(cpp_type, field.name))
00354
00355 def write_members(s, spec):
00356 """
00357 Write all the member declarations
00358
00359 @param s: The stream to write to
00360 @type s: stream
00361 @param spec: The message spec
00362 @type spec: roslib.msgs.MsgSpec
00363 """
00364 [write_member(s, field) for field in spec.parsed_fields()]
00365
00366 def escape_string(str):
00367 str = str.replace('\\', '\\\\')
00368 str = str.replace('"', '\\"')
00369 return str
00370
00371 def write_constant_declaration(s, constant):
00372 """
00373 Write a constant value as a static member
00374
00375 @param s: The stream to write to
00376 @type s: stream
00377 @param constant: The constant
00378 @type constant: roslib.msgs.Constant
00379 """
00380
00381
00382 if (constant.type in ['byte', 'int8', 'int16', 'int32', 'int64', 'char', 'uint8', 'uint16', 'uint32', 'uint64']):
00383 s.write(' enum { %s = %s };\n'%(constant.name, constant.val))
00384 else:
00385 s.write(' static const %s %s;\n'%(msg_type_to_cpp(constant.type), constant.name))
00386
00387 def write_constant_declarations(s, spec):
00388 """
00389 Write all the constants from a spec as static members
00390
00391 @param s: The stream to write to
00392 @type s: stream
00393 @param spec: The message spec
00394 @type spec: roslib.msgs.MsgSpec
00395 """
00396 [write_constant_declaration(s, constant) for constant in spec.constants]
00397 s.write('\n')
00398
00399 def write_constant_definition(s, spec, constant):
00400 """
00401 Write a constant value as a static member
00402
00403 @param s: The stream to write to
00404 @type s: stream
00405 @param constant: The constant
00406 @type constant: roslib.msgs.Constant
00407 """
00408
00409
00410 if (constant.type not in ['byte', 'int8', 'int16', 'int32', 'int64', 'char', 'uint8', 'uint16', 'uint32', 'uint64', 'string']):
00411 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))
00412 elif (constant.type == 'string'):
00413 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)))
00414
00415 def write_constant_definitions(s, spec):
00416 """
00417 Write all the constants from a spec as static members
00418
00419 @param s: The stream to write to
00420 @type s: stream
00421 @param spec: The message spec
00422 @type spec: roslib.msgs.MsgSpec
00423 """
00424 [write_constant_definition(s, spec, constant) for constant in spec.constants]
00425 s.write('\n')
00426
00427 def is_fixed_length(spec):
00428 """
00429 Returns whether or not the message is fixed-length
00430
00431 @param spec: The message spec
00432 @type spec: roslib.msgs.MsgSpec
00433 @param package: The package of the
00434 @type package: str
00435 """
00436 types = []
00437 for field in spec.parsed_fields():
00438 if (field.is_array and field.array_len is None):
00439 return False
00440
00441 if (field.base_type == 'string'):
00442 return False
00443
00444 if (not field.is_builtin):
00445 types.append(field.base_type)
00446
00447 types = set(types)
00448 for type in types:
00449 type = roslib.msgs.resolve_type(type, spec.package)
00450 (_, new_spec) = roslib.msgs.load_by_type(type, spec.package)
00451 if (not is_fixed_length(new_spec)):
00452 return False
00453
00454 return True
00455
00456 def write_deprecated_member_functions(s, spec, traits):
00457 """
00458 Writes the deprecated member functions for backwards compatibility
00459 """
00460 for field in spec.parsed_fields():
00461 if (field.is_array):
00462 s.write(' ROS_DEPRECATED uint32_t get_%s_size() const { return (uint32_t)%s.size(); }\n'%(field.name, field.name))
00463
00464 if (field.array_len is None):
00465 s.write(' ROS_DEPRECATED void set_%s_size(uint32_t size) { %s.resize((size_t)size); }\n'%(field.name, field.name))
00466 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))
00467 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))
00468
00469 for k, v in traits.items():
00470 s.write('private:\n')
00471 s.write(' static const char* __s_get%s_() { return "%s"; }\n'%(k, v))
00472 s.write('public:\n')
00473 s.write(' ROS_DEPRECATED static const std::string __s_get%s() { return __s_get%s_(); }\n\n'%(k, k))
00474 s.write(' ROS_DEPRECATED const std::string __get%s() const { return __s_get%s_(); }\n\n'%(k, k))
00475
00476 s.write(' ROS_DEPRECATED virtual uint8_t *serialize(uint8_t *write_ptr, uint32_t seq) const\n {\n')
00477 s.write(' ros::serialization::OStream stream(write_ptr, 1000000000);\n')
00478 for field in spec.parsed_fields():
00479 s.write(' ros::serialization::serialize(stream, %s);\n'%(field.name))
00480 s.write(' return stream.getData();\n }\n\n')
00481
00482 s.write(' ROS_DEPRECATED virtual uint8_t *deserialize(uint8_t *read_ptr)\n {\n')
00483 s.write(' ros::serialization::IStream stream(read_ptr, 1000000000);\n');
00484 for field in spec.parsed_fields():
00485 s.write(' ros::serialization::deserialize(stream, %s);\n'%(field.name))
00486 s.write(' return stream.getData();\n }\n\n')
00487
00488 s.write(' ROS_DEPRECATED virtual uint32_t serializationLength() const\n {\n')
00489 s.write(' uint32_t size = 0;\n');
00490 for field in spec.parsed_fields():
00491 s.write(' size += ros::serialization::serializationLength(%s);\n'%(field.name))
00492 s.write(' return size;\n }\n\n')
00493
00494 def compute_full_text_escaped(gen_deps_dict):
00495 """
00496 Same as roslib.gentools.compute_full_text, except that the
00497 resulting text is escaped to be safe for C++ double quotes
00498
00499 @param get_deps_dict: dictionary returned by get_dependencies call
00500 @type get_deps_dict: dict
00501 @return: concatenated text for msg/srv file and embedded msg/srv types. Text will be escaped for double quotes
00502 @rtype: str
00503 """
00504 definition = roslib.gentools.compute_full_text(gen_deps_dict)
00505 lines = definition.split('\n')
00506 s = StringIO()
00507 for line in lines:
00508 line = escape_string(line)
00509 s.write('%s\\n\\\n'%(line))
00510
00511 val = s.getvalue()
00512 s.close()
00513 return val
00514
00515 def is_hex_string(str):
00516 for c in str:
00517 if c not in '0123456789abcdefABCDEF':
00518 return False
00519
00520 return True
00521
00522 def write_trait_char_class(s, class_name, cpp_msg_with_alloc, value, write_static_hex_value = False):
00523 """
00524 Writes a class trait for traits which have static value() members that return const char*
00525
00526 e.g. write_trait_char_class(s, "MD5Sum", "std_msgs::String_<ContainerAllocator>", "hello") yields:
00527 template<class ContainerAllocator>
00528 struct MD5Sum<std_msgs::String_<ContainerAllocator> >
00529 {
00530 static const char* value() { return "hello"; }
00531 static const char* value(const std_msgs::String_<ContainerAllocator>&) { return value(); }
00532 };
00533
00534 @param s: The stream to write to
00535 @type s: stream
00536 @param class_name: The name of the trait class to write
00537 @type class_name: str
00538 @param cpp_msg_with_alloc: The C++ declaration of the message, including the allocator template
00539 @type cpp_msg_with_alloc: str
00540 @param value: The value to return in the string
00541 @type value: str
00542 @param write_static_hex_value: Whether or not to write a set of compile-time-checkable static values. Useful for,
00543 for example, MD5Sum. Writes static const uint64_t static_value1... static_valueN
00544 @type write_static_hex_value: bool
00545 @raise ValueError if write_static_hex_value is True but value contains characters invalid in a hex value
00546 """
00547 s.write('template<class ContainerAllocator>\nstruct %s<%s> {\n'%(class_name, cpp_msg_with_alloc))
00548 s.write(' static const char* value() \n {\n return "%s";\n }\n\n'%(value))
00549 s.write(' static const char* value(const %s&) { return value(); } \n'%(cpp_msg_with_alloc))
00550 if (write_static_hex_value):
00551 if (not is_hex_string(value)):
00552 raise ValueError('%s is not a hex value'%(value))
00553
00554 iter_count = len(value) / 16
00555 for i in range(0, int(iter_count)):
00556 start = i*16
00557 s.write(' static const uint64_t static_value%s = 0x%sULL;\n'%((i+1), value[start:start+16]))
00558 s.write('};\n\n')
00559
00560 def write_trait_true_class(s, class_name, cpp_msg_with_alloc):
00561 """
00562 Writes a true/false trait class
00563
00564 @param s: stream to write to
00565 @type s: stream
00566 @param class_name: Name of the trait class
00567 @type class_name: str
00568 @param cpp_msg_with_alloc: The C++ declaration of the message, including the allocator template
00569 @type cpp_msg_with_alloc: str
00570 """
00571 s.write('template<class ContainerAllocator> struct %s<%s> : public TrueType {};\n'%(class_name, cpp_msg_with_alloc))
00572
00573 def write_traits(s, spec, cpp_name_prefix, datatype = None, rospack=None):
00574 """
00575 Writes all the traits classes for a message
00576
00577 @param s: The stream to write to
00578 @type s: stream
00579 @param spec: The message spec
00580 @type spec: roslib.msgs.MsgSpec
00581 @param cpp_name_prefix: The C++ prefix to prepend to a message to refer to it (e.g. "std_msgs::")
00582 @type cpp_name_prefix: str
00583 @param datatype: The string to write as the datatype of the message. If None (default), pkg/msg is used.
00584 @type datatype: str
00585 """
00586
00587 gendeps_dict = roslib.gentools.get_dependencies(spec, spec.package, compute_files=False, rospack=rospack)
00588 md5sum = roslib.gentools.compute_md5(gendeps_dict, rospack=rospack)
00589 full_text = compute_full_text_escaped(gendeps_dict)
00590
00591 if (datatype is None):
00592 datatype = '%s'%(spec.full_name)
00593
00594 (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, spec.short_name)
00595 s.write('namespace ros\n{\n')
00596 s.write('namespace message_traits\n{\n')
00597
00598 write_trait_true_class(s, 'IsMessage', cpp_msg_with_alloc)
00599 write_trait_true_class(s, 'IsMessage', cpp_msg_with_alloc + " const")
00600
00601 write_trait_char_class(s, 'MD5Sum', cpp_msg_with_alloc, md5sum, True)
00602 write_trait_char_class(s, 'DataType', cpp_msg_with_alloc, datatype)
00603 write_trait_char_class(s, 'Definition', cpp_msg_with_alloc, full_text)
00604
00605 if (spec.has_header()):
00606 write_trait_true_class(s, 'HasHeader', cpp_msg_with_alloc)
00607 write_trait_true_class(s, 'HasHeader', ' const' + cpp_msg_with_alloc)
00608
00609 if (is_fixed_length(spec)):
00610 write_trait_true_class(s, 'IsFixedSize', cpp_msg_with_alloc)
00611
00612 s.write('} // namespace message_traits\n')
00613 s.write('} // namespace ros\n\n')
00614
00615 def write_operations(s, spec, cpp_name_prefix):
00616 (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, spec.short_name)
00617 s.write('namespace ros\n{\n')
00618 s.write('namespace message_operations\n{\n')
00619
00620
00621 s.write('\ntemplate<class ContainerAllocator>\nstruct Printer<%s>\n{\n'%(cpp_msg_with_alloc))
00622 s.write(' template<typename Stream> static void stream(Stream& s, const std::string& indent, const %s& v) \n {\n'%cpp_msg_with_alloc)
00623 for field in spec.parsed_fields():
00624 cpp_type = msg_type_to_cpp(field.base_type)
00625 if (field.is_array):
00626 s.write(' s << indent << "%s[]" << std::endl;\n'%(field.name))
00627 s.write(' for (size_t i = 0; i < v.%s.size(); ++i)\n {\n'%(field.name))
00628 s.write(' s << indent << " %s[" << i << "]: ";\n'%field.name)
00629 indent_increment = ' '
00630 if (not field.is_builtin):
00631 s.write(' s << std::endl;\n')
00632 s.write(' s << indent;\n')
00633 indent_increment = ' ';
00634 s.write(' Printer<%s>::stream(s, indent + "%s", v.%s[i]);\n'%(cpp_type, indent_increment, field.name))
00635 s.write(' }\n')
00636 else:
00637 s.write(' s << indent << "%s: ";\n'%field.name)
00638 indent_increment = ' '
00639 if (not field.is_builtin or field.is_array):
00640 s.write('s << std::endl;\n')
00641 s.write(' Printer<%s>::stream(s, indent + "%s", v.%s);\n'%(cpp_type, indent_increment, field.name))
00642 s.write(' }\n')
00643 s.write('};\n\n')
00644
00645 s.write('\n')
00646
00647 s.write('} // namespace message_operations\n')
00648 s.write('} // namespace ros\n\n')
00649
00650 def write_serialization(s, spec, cpp_name_prefix):
00651 """
00652 Writes the Serializer class for a message
00653
00654 @param s: Stream to write to
00655 @type s: stream
00656 @param spec: The message spec
00657 @type spec: roslib.msgs.MsgSpec
00658 @param cpp_name_prefix: The C++ prefix to prepend to a message to refer to it (e.g. "std_msgs::")
00659 @type cpp_name_prefix: str
00660 """
00661 (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, spec.short_name)
00662
00663 s.write('namespace ros\n{\n')
00664 s.write('namespace serialization\n{\n\n')
00665
00666 s.write('template<class ContainerAllocator> struct Serializer<%s>\n{\n'%(cpp_msg_with_alloc))
00667
00668 s.write(' template<typename Stream, typename T> inline static void allInOne(Stream& stream, T m)\n {\n')
00669 for field in spec.parsed_fields():
00670 s.write(' stream.next(m.%s);\n'%(field.name))
00671 s.write(' }\n\n')
00672
00673 s.write(' ROS_DECLARE_ALLINONE_SERIALIZER;\n')
00674
00675 s.write('}; // struct %s_\n'%(spec.short_name))
00676
00677 s.write('} // namespace serialization\n')
00678 s.write('} // namespace ros\n\n')
00679
00680 def write_ostream_operator(s, spec, cpp_name_prefix):
00681 (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, spec.short_name)
00682 s.write('template<typename ContainerAllocator>\nstd::ostream& operator<<(std::ostream& s, const %s& v)\n{\n'%(cpp_msg_with_alloc))
00683 s.write(' ros::message_operations::Printer<%s>::stream(s, "", v);\n return s;}\n\n'%(cpp_msg_with_alloc))
00684
00685 def generate(msg_path):
00686 """
00687 Generate a message
00688
00689 @param msg_path: The path to the .msg file
00690 @type msg_path: str
00691 """
00692 (package_dir, package) = roslib.packages.get_dir_pkg(msg_path)
00693 (_, spec) = roslib.msgs.load_from_file(msg_path, package)
00694
00695 s = StringIO()
00696 write_begin(s, spec, msg_path)
00697 write_generic_includes(s)
00698 write_includes(s, spec)
00699
00700 cpp_prefix = '%s::'%(package)
00701
00702 s.write('namespace %s\n{\n'%(package))
00703 write_struct(s, spec, cpp_prefix)
00704 write_constant_definitions(s, spec)
00705 write_ostream_operator(s, spec, cpp_prefix)
00706 s.write('} // namespace %s\n\n'%(package))
00707
00708 rospack = RosPack()
00709 write_traits(s, spec, cpp_prefix, rospack=rospack)
00710 write_serialization(s, spec, cpp_prefix)
00711 write_operations(s, spec, cpp_prefix)
00712
00713
00714
00715
00716 if (package == "std_msgs" and spec.short_name == "Header"):
00717 s.write("#define STD_MSGS_INCLUDING_HEADER_DEPRECATED_DEF 1\n")
00718 s.write("#include <std_msgs/header_deprecated_def.h>\n")
00719 s.write("#undef STD_MSGS_INCLUDING_HEADER_DEPRECATED_DEF\n\n")
00720
00721 write_end(s, spec)
00722
00723 output_dir = '%s/msg_gen/cpp/include/%s'%(package_dir, package)
00724 if (not os.path.exists(output_dir)):
00725
00726
00727 try:
00728 os.makedirs(output_dir)
00729 except OSError as e:
00730 pass
00731
00732 f = open('%s/%s.h'%(output_dir, spec.short_name), 'w')
00733 f.write(s.getvalue() + "\n")
00734
00735 s.close()
00736
00737 def generate_messages(argv):
00738 for arg in argv[1:]:
00739 generate(arg)
00740
00741 if __name__ == "__main__":
00742 roslib.msgs.set_verbose(False)
00743 generate_messages(sys.argv)
00744