fix bounded arrays

fix bounded arrays

// generated from rosidl_generator_py/resource/_msg_support.c.em
// generated code does not contain a copyright notice

#include <Python.h>

#include <@(spec.base_type.pkg_name)/@(subfolder)/@(module_name)__struct.h>
#include <@(spec.base_type.pkg_name)/@(subfolder)/@(module_name)__functions.h>

@{
have_not_included_primitive_arrays = True
have_not_included_string = True
nested_array_dict = {}
}@
@[for field in spec.fields]@
@[  if field.type.is_array and have_not_included_primitive_arrays]@
@{have_not_included_primitive_arrays = False}@
#include <rosidl_generator_c/primitives_array.h>
#include <rosidl_generator_c/primitives_array_functions.h>

@[  end if]@
@[  if field.type.type == 'string' and have_not_included_string]@
@{have_not_included_string = False}@
#include <rosidl_generator_c/string.h>
#include <rosidl_generator_c/string_functions.h>

@[  end if]@
@{
if not field.type.is_primitive_type() and field.type.is_array:
    if field.type.type not in nested_array_dict:
        nested_array_dict[field.type.type] = field.type.pkg_name
}@
@[end for]@
@[if nested_array_dict != {}]@
// Nested array functions includes
@[  for key in nested_array_dict]@
#include <@(nested_array_dict[key])/@(subfolder)/@convert_camel_case_to_lower_case_underscore(key)__functions.h>
@[  end for]@
// end nested array functions include
@[end if]@
@{
msg_typename = '%s__%s__%s' % (spec.base_type.pkg_name, subfolder, spec.base_type.type)
}@

void * @(spec.base_type.pkg_name)_@(module_name)__convert_from_py(PyObject * _pymsg)
{
  @(msg_typename) * ros_message = @(msg_typename)__create();
  (void)ros_message;
@{
full_classname = "@(spec.base_type.pkg_name).@(subfolder)._@(module_name).@(spec.base_type.type)"
}@
  char full_classname_dest[@(len(full_classname) + 1)];

  char * class_name = (char *)PyUnicode_1BYTE_DATA(
    PyObject_GetAttrString(PyObject_GetAttrString(_pymsg, "__class__"), "__name__"));
  char * module_name = (char *)PyUnicode_1BYTE_DATA(
    PyObject_GetAttrString(PyObject_GetAttrString(_pymsg, "__class__"), "__module__"));

  snprintf(full_classname_dest, sizeof(full_classname_dest), "%s.%s", class_name, module_name);

  // TODO(dirk-thomas) The check seems to be wrong, asserting that the strings are not equal?
  assert(strncmp(
      "@(spec.base_type.pkg_name).@(subfolder)._@(module_name).@(spec.base_type.type)",
      full_classname_dest, @(len(full_classname))));

@[for field in spec.fields]@
  PyObject * py@(field.name) = PyObject_GetAttrString(_pymsg, "@(field.name)");
@[  if not field.type.is_primitive_type()]@
@{
nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type)
}@
  PyObject * py@(field.name)_msg_module = PyImport_ImportModule("@(field.type.pkg_name).msg._@convert_camel_case_to_lower_case_underscore(field.type.type)");
  PyObject * py@(field.name)_convert_from_py = PyObject_GetAttrString(py@(field.name)_msg_module, "_convert_from_py");
  typedef PyObject *(* convert_from_py_signature)(void *);
  convert_from_py_signature convert_from_py_@(field.name) = (convert_from_py_signature)PyCapsule_GetPointer(py@(field.name)_convert_from_py, NULL);
@[    if field.type.is_array]@
  assert(PySequence_Check(py@(field.name)));
  PyObject * seq@(field.name) = PySequence_Fast(py@(field.name), "expected a sequence");
  @(nested_type) * item@(field.name);
@[      if field.type.array_size is None]@
  size_t size@(field.name) = PySequence_Size(py@(field.name));
  if (!@(nested_type)__Array__init(&(ros_message->@(field.name)), size@(field.name))) {
    PyErr_SetString(PyExc_RuntimeError, "unable to create @(nested_type)__Array ros_message");
  }
  @(nested_type) * dest@(field.name) = ros_message->@(field.name).data;
@[      else]@
  size_t size@(field.name) = @(field.type.array_size);
@[        if field.type.is_upper_bound]@
  @(nested_type) * dest@(field.name) = ros_message->@(field.name).data;
@[        else]@
  @(nested_type) * dest@(field.name) = ros_message->@(field.name);
@[        end if]@
@[      end if]@
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
    item@(field.name) = (@(nested_type) *) convert_from_py_@(field.name)(
      PySequence_Fast_GET_ITEM(seq@(field.name), idx@(field.name)));
    memcpy(&dest@(field.name)[idx@(field.name)], item@(field.name), sizeof(@(nested_type)));
  }
@[    else]@
  @(nested_type) * tmp@(field.name) = (@(nested_type) *) convert_from_py_@(field.name)(py@(field.name));
  ros_message->@(field.name) = *tmp@(field.name);
@[    end if]@
@[  elif field.type.is_array]@
  assert(PySequence_Check(py@(field.name)));
  PyObject * seq@(field.name) = PySequence_Fast(py@(field.name), "expected a sequence");
  PyObject * item@(field.name);
@[    if field.type.array_size is None]@
  size_t size@(field.name) = PySequence_Size(py@(field.name));
@[      if field.type.type == 'string']@
  if (!rosidl_generator_c__String__Array__init(&(ros_message->@(field.name)), size@(field.name))) {
    PyErr_SetString(PyExc_RuntimeError, "unable to create String__Array ros_message");
  }
@[      else]@
  if (!rosidl_generator_c__@(field.type.type)__Array__init(&(ros_message->@(field.name)), size@(field.name))) {
    PyErr_SetString(PyExc_RuntimeError, "unable to create @(field.type.type)__Array ros_message");
  }
@[      end if]@
  @primitive_msg_type_to_c(field.type.type) * dest@(field.name) = ros_message->@(field.name).data;
@[    else]@
  size_t size@(field.name) = @(field.type.array_size);
@[        if field.type.is_upper_bound]@
  @primitive_msg_type_to_c(field.type.type) * dest@(field.name) = ros_message->@(field.name).data;
@[        else]@
  @primitive_msg_type_to_c(field.type.type) * dest@(field.name) = ros_message->@(field.name);
@[        end if]@
@[    end if]@
@[    if field.type.type != 'string']@
  @primitive_msg_type_to_c(field.type.type) tmp@(field.name);
@[    end if]@
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
    item@(field.name) = PySequence_Fast_GET_ITEM(seq@(field.name), idx@(field.name));
@[    if field.type.type == 'char']@
    assert(PyUnicode_Check(item@(field.name)));
    tmp@(field.name) = PyUnicode_1BYTE_DATA(item@(field.name))[0];
@[    elif field.type.type == 'byte']@
    assert(PyBytes_Check(item@(field.name)));
    tmp@(field.name) = PyBytes_AS_STRING(item@(field.name))[0];
@[    elif field.type.type == 'string']@
    assert(PyUnicode_Check(item@(field.name)));
    rosidl_generator_c__String__assign(
      &dest@(field.name)[idx@(field.name)], (char *)PyUnicode_1BYTE_DATA(item@(field.name)));
@[    elif field.type.type == 'bool']@
    assert(PyBool_Check(item@(field.name)));
    tmp@(field.name) = (item@(field.name) == Py_True);
@[    elif field.type.type in ['float32', 'float64']]@
    assert(PyFloat_Check(item@(field.name)));
@[      if field.type.type == 'float32']@
    tmp@(field.name) = (float)PyFloat_AS_DOUBLE(item@(field.name));
@[      else]@
    tmp@(field.name) = PyFloat_AS_DOUBLE(item@(field.name));
@[      end if]@
@[    elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
    assert(PyLong_Check(item@(field.name)));
    tmp@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsLong(item@(field.name));
@[    elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
    assert(PyLong_Check(item@(field.name)));
@[      if field.type.type == 'uint32']@
    tmp@(field.name) = PyLong_AsUnsignedLong(item@(field.name));
@[      else]@
    tmp@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsUnsignedLong(item@(field.name));
@[      end if]
@[    elif field.type.type == 'int64']@
    assert(PyLong_Check(item@(field.name)));
    tmp@(field.name) = PyLong_AsLongLong(item@(field.name));
@[    elif field.type.type == 'uint64']@
    assert(PyLong_Check(item@(field.name)));
    tmp@(field.name) = PyLong_AsUnsignedLongLong(item@(field.name));
@[    end if]@
@[    if field.type.type != 'string']@
    memcpy(&dest@(field.name)[idx@(field.name)], &tmp@(field.name), sizeof(@primitive_msg_type_to_c(field.type.type)));
@[    end if]@
  }
@[  elif field.type.type == 'char']@
  assert(PyUnicode_Check(py@(field.name)));
  ros_message->@(field.name) = PyUnicode_1BYTE_DATA(py@(field.name))[0];
@[  elif field.type.type == 'byte']@
  assert(PyBytes_Check(py@(field.name)));
  ros_message->@(field.name) = PyBytes_AsString(py@(field.name))[0];
@[  elif field.type.type == 'string']@
  assert(PyUnicode_Check(py@(field.name)));
  rosidl_generator_c__String__assign(
    &ros_message->@(field.name), (char *)PyUnicode_1BYTE_DATA(py@(field.name)));
@[  elif field.type.type == 'bool']@
  assert(PyBool_Check(py@(field.name)));
  ros_message->@(field.name) = (Py_True == py@(field.name));
@[  elif field.type.type in ['float32', 'float64']]@
  assert(PyFloat_Check(py@(field.name)));
@[    if field.type.type == 'float32']@
  ros_message->@(field.name) = (float)PyFloat_AS_DOUBLE(py@(field.name));
@[    else]@
  ros_message->@(field.name) = PyFloat_AS_DOUBLE(py@(field.name));
@[    end if]@
@[  elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
  assert(PyLong_Check(py@(field.name)));
  ros_message->@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsLong(py@(field.name));
@[  elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
  assert(PyLong_Check(py@(field.name)));
@[    if field.type.type == 'uint32']@
  ros_message->@(field.name) = PyLong_AsUnsignedLong(py@(field.name));
@[    else]@
  ros_message->@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsUnsignedLong(py@(field.name));
@[    end if]@
@[  elif field.type.type == 'int64']@
  assert(PyLong_Check(py@(field.name)));
  ros_message->@(field.name) = PyLong_AsLongLong(py@(field.name));
@[  elif field.type.type == 'uint64']@
  assert(PyLong_Check(py@(field.name)));
  ros_message->@(field.name) = PyLong_AsUnsignedLongLong(py@(field.name));
@[  else]@
  assert(false);
@[  end if]@
@[end for]@

  assert(ros_message != NULL);
  return ros_message;
}

PyObject * @(spec.base_type.pkg_name)_@(module_name)__convert_to_py(void * raw_ros_message)
{
  @(msg_typename) * ros_message = (@(msg_typename) *)raw_ros_message;
  (void)ros_message;

  PyObject * pymessage_module = PyImport_ImportModule("@(spec.base_type.pkg_name).@(subfolder)._@(module_name)");
  PyObject * pymessage_class = PyObject_GetAttrString(pymessage_module, "@(spec.base_type.type)");

  /* NOTE(esteve): Call constructor of @(spec.base_type.type) */
  PyObject * _pymessage = NULL;
  _pymessage = PyObject_CallObject(pymessage_class, NULL);
  assert(_pymessage != NULL);

@[for field in spec.fields]@
  PyObject * py@(field.name) = NULL;
@[  if not field.type.is_primitive_type()]@
@{
nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type)
}@
  PyObject * py@(field.name)_msg_module = PyImport_ImportModule("@(field.type.pkg_name).msg._@convert_camel_case_to_lower_case_underscore(field.type.type)");
  PyObject * py@(field.name)_convert_to_py = PyObject_GetAttrString(py@(field.name)_msg_module, "_convert_to_py");
  typedef PyObject *(* convert_to_py_signature)(void *);
  convert_to_py_signature convert_to_py_@(field.name) = (convert_to_py_signature)PyCapsule_GetPointer(py@(field.name)_convert_to_py, NULL);
@[    if field.type.is_array]@
@[      if field.type.array_size is None]@
  size_t size@(field.name) = ros_message->@(field.name).size;
@[      else]@
  size_t size@(field.name) = @(field.type.array_size);
@[      end if]@
  py@(field.name) = PyList_New(size@(field.name));
  @(nested_type) item@(field.name);
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
@[      if field.type.array_size is None or field.type.is_upper_bound]@
    item@(field.name) = ros_message->@(field.name).data[idx@(field.name)];
@[      else]@
    item@(field.name) = ros_message->@(field.name)[idx@(field.name)];
@[      end if]@
    PyList_SetItem(py@(field.name), idx@(field.name), convert_to_py_@(field.name)(&item@(field.name)));
  }
  assert(PySequence_Check(py@(field.name)));
@[    else]@
  @(nested_type) pytmp@(field.name) = ros_message->@(field.name);
  py@(field.name) = convert_to_py_@(field.name)(&pytmp@(field.name));
@[    end if]@
@[  elif field.type.is_array]@
@[    if field.type.array_size is None]@
  size_t size@(field.name) = ros_message->@(field.name).size;
  @primitive_msg_type_to_c(field.type.type) * tmpmessagedata@(field.name) = ros_message->@(field.name).data;
@[    else]@
  size_t size@(field.name) = @(field.type.array_size);
@[      if field.type.is_upper_bound]@
  @primitive_msg_type_to_c(field.type.type) * tmpmessagedata@(field.name) = ros_message->@(field.name).data;
@[      else]@
  @primitive_msg_type_to_c(field.type.type) * tmpmessagedata@(field.name) = ros_message->@(field.name);
@[      end if]@
@[    end if]@
  py@(field.name) = PyList_New(size@(field.name));
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
@[    if field.type.type == 'char']@
    PyList_SetItem(py@(field.name), idx@(field.name),
      PyUnicode_FromStringAndSize(&tmpmessagedata@(field.name)[idx@(field.name)], 1));
@[    elif field.type.type == 'byte']@
    PyList_SetItem(py@(field.name), idx@(field.name),
      PyBytes_FromStringAndSize((const char *)&tmpmessagedata@(field.name)[idx@(field.name)], 1));
@[    elif field.type.type == 'string']@
    PyList_SetItem(py@(field.name), idx@(field.name), PyUnicode_FromString(tmpmessagedata@(field.name)[idx@(field.name)].data));
@[    elif field.type.type == 'bool']@
    PyList_SetItem(py@(field.name), idx@(field.name), tmpmessagedata@(field.name)[idx@(field.name)] ? Py_True : Py_False);
@[    elif field.type.type in ['float32', 'float64']]@
    PyList_SetItem(py@(field.name), idx@(field.name), PyFloat_FromDouble(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromUnsignedLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type == 'int64']@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromLongLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type == 'uint64']@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromUnsignedLongLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    end if]@
  }
  assert(PySequence_Check(py@(field.name)));
@[  elif field.type.type == 'char']@
  py@(field.name) = PyUnicode_FromStringAndSize(&ros_message->@(field.name), 1);
@[  elif field.type.type == 'byte']@
  py@(field.name) = PyBytes_FromStringAndSize((const char *)&ros_message->@(field.name), 1);
@[  elif field.type.type == 'string']@
  py@(field.name) = PyUnicode_FromString(ros_message->@(field.name).data);
@[  elif field.type.type == 'bool']@
  py@(field.name) = ros_message->@(field.name) ? Py_True : Py_False;
@[  elif field.type.type in ['float32', 'float64']]@
  py@(field.name) = PyFloat_FromDouble(ros_message->@(field.name));
@[  elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
  py@(field.name) = PyLong_FromLong(ros_message->@(field.name));
@[  elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
  py@(field.name) = PyLong_FromUnsignedLong(ros_message->@(field.name));
@[  elif field.type.type == 'int64']@
  py@(field.name) = PyLong_FromLongLong(ros_message->@(field.name));
@[  elif field.type.type == 'uint64']@
  py@(field.name) = PyLong_FromUnsignedLongLong(ros_message->@(field.name));
@[  else]@
  assert(false);
@[  end if]@
  assert(py@(field.name) != NULL);
  Py_INCREF(py@(field.name));
  PyObject_SetAttrString(_pymessage, "@(field.name)", py@(field.name));
@[end for]@
  assert(_pymessage != NULL);
  return _pymessage;
}

// generated from rosidl_generator_py/resource/_msg_support.c.em
// generated code does not contain a copyright notice

#include <Python.h>

#include <@(spec.base_type.pkg_name)/@(subfolder)/@(module_name)__struct.h>
#include <@(spec.base_type.pkg_name)/@(subfolder)/@(module_name)__functions.h>

@{
have_not_included_primitive_arrays = True
have_not_included_string = True
nested_array_dict = {}
}@
@[for field in spec.fields]@
@[  if field.type.is_array and have_not_included_primitive_arrays]@
@{have_not_included_primitive_arrays = False}@
#include <rosidl_generator_c/primitives_array.h>
#include <rosidl_generator_c/primitives_array_functions.h>

@[  end if]@
@[  if field.type.type == 'string' and have_not_included_string]@
@{have_not_included_string = False}@
#include <rosidl_generator_c/string.h>
#include <rosidl_generator_c/string_functions.h>

@[  end if]@
@{
if not field.type.is_primitive_type() and field.type.is_array:
    if field.type.type not in nested_array_dict:
        nested_array_dict[field.type.type] = field.type.pkg_name
}@
@[end for]@
@[if nested_array_dict != {}]@
// Nested array functions includes
@[  for key in nested_array_dict]@
#include <@(nested_array_dict[key])/@(subfolder)/@convert_camel_case_to_lower_case_underscore(key)__functions.h>
@[  end for]@
// end nested array functions include
@[end if]@
@{
msg_typename = '%s__%s__%s' % (spec.base_type.pkg_name, subfolder, spec.base_type.type)
}@

void * @(spec.base_type.pkg_name)_@(module_name)__convert_from_py(PyObject * _pymsg)
{
  @(msg_typename) * ros_message = @(msg_typename)__create();
  (void)ros_message;
@{
full_classname = "@(spec.base_type.pkg_name).@(subfolder)._@(module_name).@(spec.base_type.type)"
}@
  char full_classname_dest[@(len(full_classname) + 1)];

  char * class_name = (char *)PyUnicode_1BYTE_DATA(
    PyObject_GetAttrString(PyObject_GetAttrString(_pymsg, "__class__"), "__name__"));
  char * module_name = (char *)PyUnicode_1BYTE_DATA(
    PyObject_GetAttrString(PyObject_GetAttrString(_pymsg, "__class__"), "__module__"));

  snprintf(full_classname_dest, sizeof(full_classname_dest), "%s.%s", class_name, module_name);

  // TODO(dirk-thomas) The check seems to be wrong, asserting that the strings are not equal?
  assert(strncmp(
      "@(spec.base_type.pkg_name).@(subfolder)._@(module_name).@(spec.base_type.type)",
      full_classname_dest, @(len(full_classname))));

@[for field in spec.fields]@
  PyObject * py@(field.name) = PyObject_GetAttrString(_pymsg, "@(field.name)");
@[  if not field.type.is_primitive_type()]@
@{
nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type)
}@
  PyObject * py@(field.name)_msg_module = PyImport_ImportModule("@(field.type.pkg_name).msg._@convert_camel_case_to_lower_case_underscore(field.type.type)");
  PyObject * py@(field.name)_convert_from_py = PyObject_GetAttrString(py@(field.name)_msg_module, "_convert_from_py");
  typedef PyObject *(* convert_from_py_signature)(void *);
  convert_from_py_signature convert_from_py_@(field.name) = (convert_from_py_signature)PyCapsule_GetPointer(py@(field.name)_convert_from_py, NULL);
@[    if field.type.is_array]@
  assert(PySequence_Check(py@(field.name)));
  PyObject * seq@(field.name) = PySequence_Fast(py@(field.name), "expected a sequence");
  @(nested_type) * item@(field.name);
@[      if field.type.array_size is None]@
  size_t size@(field.name) = PySequence_Size(py@(field.name));
  if (!@(nested_type)__Array__init(&(ros_message->@(field.name)), size@(field.name))) {
    PyErr_SetString(PyExc_RuntimeError, "unable to create @(nested_type)__Array ros_message");
  }
  @(nested_type) * dest@(field.name) = ros_message->@(field.name).data;
@[      else]@
  size_t size@(field.name) = @(field.type.array_size);
  @(nested_type) * dest@(field.name) = ros_message->@(field.name);
@[      end if]@
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
    item@(field.name) = (@(nested_type) *) convert_from_py_@(field.name)(
      PySequence_Fast_GET_ITEM(seq@(field.name), idx@(field.name)));
    memcpy(&dest@(field.name)[idx@(field.name)], item@(field.name), sizeof(@(nested_type)));
  }
@[    else]@
  @(nested_type) * tmp@(field.name) = (@(nested_type) *) convert_from_py_@(field.name)(py@(field.name));
  ros_message->@(field.name) = *tmp@(field.name);
@[    end if]@
@[  elif field.type.is_array]@
  assert(PySequence_Check(py@(field.name)));
  PyObject * seq@(field.name) = PySequence_Fast(py@(field.name), "expected a sequence");
  PyObject * item@(field.name);
@[    if field.type.array_size is None]@
  size_t size@(field.name) = PySequence_Size(py@(field.name));
@[      if field.type.type == 'string']@
  if (!rosidl_generator_c__String__Array__init(&(ros_message->@(field.name)), size@(field.name))) {
    PyErr_SetString(PyExc_RuntimeError, "unable to create String__Array ros_message");
  }
@[      else]@
  if (!rosidl_generator_c__@(field.type.type)__Array__init(&(ros_message->@(field.name)), size@(field.name))) {
    PyErr_SetString(PyExc_RuntimeError, "unable to create @(field.type.type)__Array ros_message");
  }
@[      end if]@
  @primitive_msg_type_to_c(field.type.type) * dest@(field.name) = ros_message->@(field.name).data;
@[    else]@
  size_t size@(field.name) = @(field.type.array_size);
  @primitive_msg_type_to_c(field.type.type) * dest@(field.name) = ros_message->@(field.name);
@[    end if]@
@[    if field.type.type != 'string']@
  @primitive_msg_type_to_c(field.type.type) tmp@(field.name);
@[    end if]@
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
    item@(field.name) = PySequence_Fast_GET_ITEM(seq@(field.name), idx@(field.name));
@[    if field.type.type == 'char']@
    assert(PyUnicode_Check(item@(field.name)));
    tmp@(field.name) = PyUnicode_1BYTE_DATA(item@(field.name))[0];
@[    elif field.type.type == 'byte']@
    assert(PyBytes_Check(item@(field.name)));
    tmp@(field.name) = PyBytes_AS_STRING(item@(field.name))[0];
@[    elif field.type.type == 'string']@
    assert(PyUnicode_Check(item@(field.name)));
    rosidl_generator_c__String__assign(
      &dest@(field.name)[idx@(field.name)], (char *)PyUnicode_1BYTE_DATA(item@(field.name)));
@[    elif field.type.type == 'bool']@
    assert(PyBool_Check(item@(field.name)));
    tmp@(field.name) = (item@(field.name) == Py_True);
@[    elif field.type.type in ['float32', 'float64']]@
    assert(PyFloat_Check(item@(field.name)));
@[      if field.type.type == 'float32']@
    tmp@(field.name) = (float)PyFloat_AS_DOUBLE(item@(field.name));
@[      else]@
    tmp@(field.name) = PyFloat_AS_DOUBLE(item@(field.name));
@[      end if]@
@[    elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
    assert(PyLong_Check(item@(field.name)));
    tmp@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsLong(item@(field.name));
@[    elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
    assert(PyLong_Check(item@(field.name)));
@[      if field.type.type == 'uint32']@
    tmp@(field.name) = PyLong_AsUnsignedLong(item@(field.name));
@[      else]@
    tmp@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsUnsignedLong(item@(field.name));
@[      end if]
@[    elif field.type.type == 'int64']@
    assert(PyLong_Check(item@(field.name)));
    tmp@(field.name) = PyLong_AsLongLong(item@(field.name));
@[    elif field.type.type == 'uint64']@
    assert(PyLong_Check(item@(field.name)));
    tmp@(field.name) = PyLong_AsUnsignedLongLong(item@(field.name));
@[    end if]@
@[    if field.type.type != 'string']@
    memcpy(&dest@(field.name)[idx@(field.name)], &tmp@(field.name), sizeof(@primitive_msg_type_to_c(field.type.type)));
@[    end if]@
  }
@[  elif field.type.type == 'char']@
  assert(PyUnicode_Check(py@(field.name)));
  ros_message->@(field.name) = PyUnicode_1BYTE_DATA(py@(field.name))[0];
@[  elif field.type.type == 'byte']@
  assert(PyBytes_Check(py@(field.name)));
  ros_message->@(field.name) = PyBytes_AsString(py@(field.name))[0];
@[  elif field.type.type == 'string']@
  assert(PyUnicode_Check(py@(field.name)));
  rosidl_generator_c__String__assign(
    &ros_message->@(field.name), (char *)PyUnicode_1BYTE_DATA(py@(field.name)));
@[  elif field.type.type == 'bool']@
  assert(PyBool_Check(py@(field.name)));
  ros_message->@(field.name) = (Py_True == py@(field.name));
@[  elif field.type.type in ['float32', 'float64']]@
  assert(PyFloat_Check(py@(field.name)));
@[    if field.type.type == 'float32']@
  ros_message->@(field.name) = (float)PyFloat_AS_DOUBLE(py@(field.name));
@[    else]@
  ros_message->@(field.name) = PyFloat_AS_DOUBLE(py@(field.name));
@[    end if]@
@[  elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
  assert(PyLong_Check(py@(field.name)));
  ros_message->@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsLong(py@(field.name));
@[  elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
  assert(PyLong_Check(py@(field.name)));
@[    if field.type.type == 'uint32']@
  ros_message->@(field.name) = PyLong_AsUnsignedLong(py@(field.name));
@[    else]@
  ros_message->@(field.name) = (@(primitive_msg_type_to_c(field.type.type)))PyLong_AsUnsignedLong(py@(field.name));
@[    end if]@
@[  elif field.type.type == 'int64']@
  assert(PyLong_Check(py@(field.name)));
  ros_message->@(field.name) = PyLong_AsLongLong(py@(field.name));
@[  elif field.type.type == 'uint64']@
  assert(PyLong_Check(py@(field.name)));
  ros_message->@(field.name) = PyLong_AsUnsignedLongLong(py@(field.name));
@[  else]@
  assert(false);
@[  end if]@
@[end for]@

  assert(ros_message != NULL);
  return ros_message;
}

PyObject * @(spec.base_type.pkg_name)_@(module_name)__convert_to_py(void * raw_ros_message)
{
  @(msg_typename) * ros_message = (@(msg_typename) *)raw_ros_message;
  (void)ros_message;

  PyObject * pymessage_module = PyImport_ImportModule("@(spec.base_type.pkg_name).@(subfolder)._@(module_name)");
  PyObject * pymessage_class = PyObject_GetAttrString(pymessage_module, "@(spec.base_type.type)");

  /* NOTE(esteve): Call constructor of @(spec.base_type.type) */
  PyObject * _pymessage = NULL;
  _pymessage = PyObject_CallObject(pymessage_class, NULL);
  assert(_pymessage != NULL);

@[for field in spec.fields]@
  PyObject * py@(field.name) = NULL;
@[  if not field.type.is_primitive_type()]@
@{
nested_type = '%s__%s__%s' % (field.type.pkg_name, 'msg', field.type.type)
}@
  PyObject * py@(field.name)_msg_module = PyImport_ImportModule("@(field.type.pkg_name).msg._@convert_camel_case_to_lower_case_underscore(field.type.type)");
  PyObject * py@(field.name)_convert_to_py = PyObject_GetAttrString(py@(field.name)_msg_module, "_convert_to_py");
  typedef PyObject *(* convert_to_py_signature)(void *);
  convert_to_py_signature convert_to_py_@(field.name) = (convert_to_py_signature)PyCapsule_GetPointer(py@(field.name)_convert_to_py, NULL);
@[    if field.type.is_array]@
@[      if field.type.array_size is None]@
  size_t size@(field.name) = ros_message->@(field.name).size;
@[      else]@
  size_t size@(field.name) = @(field.type.array_size);
@[      end if]@
  py@(field.name) = PyList_New(size@(field.name));
  @(nested_type) item@(field.name);
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
@[      if field.type.array_size is None]@
    item@(field.name) = ros_message->@(field.name).data[idx@(field.name)];
@[      else]@
    item@(field.name) = ros_message->@(field.name)[idx@(field.name)];
@[      end if]@
    PyList_SetItem(py@(field.name), idx@(field.name), convert_to_py_@(field.name)(&item@(field.name)));
  }
  assert(PySequence_Check(py@(field.name)));
@[    else]@
  @(nested_type) pytmp@(field.name) = ros_message->@(field.name);
  py@(field.name) = convert_to_py_@(field.name)(&pytmp@(field.name));
@[    end if]@
@[  elif field.type.is_array]@
@[    if field.type.array_size is None]@
  size_t size@(field.name) = ros_message->@(field.name).size;
  @primitive_msg_type_to_c(field.type.type) * tmpmessagedata@(field.name) = ros_message->@(field.name).data;
@[    else]@
  size_t size@(field.name) = @(field.type.array_size);
  @primitive_msg_type_to_c(field.type.type) * tmpmessagedata@(field.name) = ros_message->@(field.name);
@[    end if]@
  py@(field.name) = PyList_New(size@(field.name));
  size_t idx@(field.name);
  for (idx@(field.name) = 0; idx@(field.name) < size@(field.name); idx@(field.name)++) {
@[    if field.type.type == 'char']@
    PyList_SetItem(py@(field.name), idx@(field.name),
      PyUnicode_FromStringAndSize(&tmpmessagedata@(field.name)[idx@(field.name)], 1));
@[    elif field.type.type == 'byte']@
    PyList_SetItem(py@(field.name), idx@(field.name),
      PyBytes_FromStringAndSize((const char *)&tmpmessagedata@(field.name)[idx@(field.name)], 1));
@[    elif field.type.type == 'string']@
    PyList_SetItem(py@(field.name), idx@(field.name), PyUnicode_FromString(tmpmessagedata@(field.name)[idx@(field.name)].data));
@[    elif field.type.type == 'bool']@
    PyList_SetItem(py@(field.name), idx@(field.name), tmpmessagedata@(field.name)[idx@(field.name)] ? Py_True : Py_False);
@[    elif field.type.type in ['float32', 'float64']]@
    PyList_SetItem(py@(field.name), idx@(field.name), PyFloat_FromDouble(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromUnsignedLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type == 'int64']@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromLongLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    elif field.type.type == 'uint64']@
    PyList_SetItem(py@(field.name), idx@(field.name), PyLong_FromUnsignedLongLong(tmpmessagedata@(field.name)[idx@(field.name)]));
@[    end if]@
  }
  assert(PySequence_Check(py@(field.name)));
@[  elif field.type.type == 'char']@
  py@(field.name) = PyUnicode_FromStringAndSize(&ros_message->@(field.name), 1);
@[  elif field.type.type == 'byte']@
  py@(field.name) = PyBytes_FromStringAndSize((const char *)&ros_message->@(field.name), 1);
@[  elif field.type.type == 'string']@
  py@(field.name) = PyUnicode_FromString(ros_message->@(field.name).data);
@[  elif field.type.type == 'bool']@
  py@(field.name) = ros_message->@(field.name) ? Py_True : Py_False;
@[  elif field.type.type in ['float32', 'float64']]@
  py@(field.name) = PyFloat_FromDouble(ros_message->@(field.name));
@[  elif field.type.type in [
        'int8',
        'int16',
        'int32',
    ]]@
  py@(field.name) = PyLong_FromLong(ros_message->@(field.name));
@[  elif field.type.type in [
        'uint8',
        'uint16',
        'uint32',
    ]]@
  py@(field.name) = PyLong_FromUnsignedLong(ros_message->@(field.name));
@[  elif field.type.type == 'int64']@
  py@(field.name) = PyLong_FromLongLong(ros_message->@(field.name));
@[  elif field.type.type == 'uint64']@
  py@(field.name) = PyLong_FromUnsignedLongLong(ros_message->@(field.name));
@[  else]@
  assert(false);
@[  end if]@
  assert(py@(field.name) != NULL);
  Py_INCREF(py@(field.name));
  PyObject_SetAttrString(_pymessage, "@(field.name)", py@(field.name));
@[end for]@
  assert(_pymessage != NULL);
  return _pymessage;
}


microRTPS: timesync: fix unit conversion

@###############################################
@#
@# EmPy template for generating microRTPS_timesync.h file
@#
@###############################################
@# Start of Template
@#
@# Context:
@#  - msgs (List) list of all msg files
@#  - multi_topics (List) list of all multi-topic names
@#  - ids (List) list of all RTPS msg ids
@###############################################
@{
import genmsg.msgs

from px_generate_uorb_topic_helper import * # this is in Tools/
from px_generate_uorb_topic_files import MsgScope # this is in Tools/

package = package[0]
fastrtpsgen_version = fastrtpsgen_version[0]
try:
    ros2_distro = ros2_distro[0].decode("utf-8")
except AttributeError:
    ros2_distro = ros2_distro[0]
}@
/****************************************************************************
 *
 * Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. Neither the name of the copyright holder 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 HOLDER 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.
 *
 ****************************************************************************/

/*!
 * @@file microRTPS_timesync.h
 * @@brief Adds time sync for the microRTPS bridge
 * @@author Nuno Marques <nuno.marques@@dronesolutions.io>
 * @@author Julian Kent <julian@@auterion.com>
 */

#pragma once

#include <atomic>
#include <functional>
#include <thread>

@[if ros2_distro]@
#include "Timesync_Publisher.h"
#include "Timesync_Subscriber.h"
@[else]@
#include "timesync_Publisher.h"
#include "timesync_Subscriber.h"
@[end if]@

static constexpr double ALPHA_INITIAL = 0.05;
static constexpr double ALPHA_FINAL = 0.003;
static constexpr double BETA_INITIAL = 0.05;
static constexpr double BETA_FINAL = 0.003;
static constexpr int WINDOW_SIZE = 500;
static constexpr int64_t UNKNOWN = 0;
static constexpr int64_t TRIGGER_RESET_THRESHOLD_NS = 100ll * 1000ll * 1000ll;
static constexpr int REQUEST_RESET_COUNTER_THRESHOLD = 5;

class TimeSync {
public:
	TimeSync();
	virtual ~TimeSync();

@[if ros2_distro]@
	void start(const Timesync_Publisher* pub);
@[else]@
	void start(const timesync_Publisher* pub);
@[end if]@

	void reset();
	void stop();

	/**
	 * Get clock monotonic time (raw) in nanoseconds
	 */
	inline int64_t getMonoRawTimeNSec() {
		timespec t;
		clock_gettime(CLOCK_MONOTONIC_RAW, &t);
		return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;
	}

	/**
	 * Get system monotonic time in microseconds
	 */
	inline int64_t getMonoTimeUSec() {
		timespec t;
		clock_gettime(CLOCK_MONOTONIC, &t);
		return (int64_t)(t.tv_sec * 1000000000LL + t.tv_nsec) / 1000LL;
	}

	bool addMeasurement(int64_t local_t1_ns, int64_t remote_t2_ns, int64_t local_t3_ns);

@[if 1.5 <= fastrtpsgen_version <= 1.7]@
@[    if ros2_distro]@
	void processTimesyncMsg(@(package)::msg::dds_::Timesync_* msg);

	@(package)::msg::dds_::Timesync_ newTimesyncMsg();
@[    else]@
	void processTimesyncMsg(timesync_* msg);

	timesync_ newTimesyncMsg();
@[    end if]@
@[else]@
@[    if ros2_distro]@
	void processTimesyncMsg(@(package)::msg::Timesync* msg);

	@(package)::msg::Timesync newTimesyncMsg();
@[    else]@
	void processTimesyncMsg(timesync* msg);

	timesync newTimesyncMsg();
@[    end if]@
@[end if]@

	inline int64_t getOffset() { return _offset_ns.load(); }
	inline void addOffset(uint64_t& timestamp) { timestamp = (timestamp * 1000LL + _offset_ns.load()) / 1000ULL; }
	inline void subtractOffset(uint64_t& timestamp) { timestamp = (timestamp * 1000LL - _offset_ns.load()) / 1000ULL; }

private:
	std::atomic<int64_t> _offset_ns;
	int64_t _skew_ns_per_sync;
	int64_t _num_samples;

	int32_t _request_reset_counter;
	uint8_t _last_msg_seq;
	uint8_t _last_remote_msg_seq;

@[if ros2_distro]@
	Timesync_Publisher _timesync_pub;
	Timesync_Subscriber _timesync_sub;
@[else]@
	timesync_Publisher _timesync_pub;
	timesync_Subscriber _timesync_sub;
@[end if]@

	std::unique_ptr<std::thread> _send_timesync_thread;
	std::atomic<bool> _request_stop{false};

	inline void updateOffset(const uint64_t& offset) { _offset_ns.store(offset, std::memory_order_relaxed); }
};

@###############################################
@#
@# EmPy template for generating microRTPS_timesync.h file
@#
@###############################################
@# Start of Template
@#
@# Context:
@#  - msgs (List) list of all msg files
@#  - multi_topics (List) list of all multi-topic names
@#  - ids (List) list of all RTPS msg ids
@###############################################
@{
import genmsg.msgs

from px_generate_uorb_topic_helper import * # this is in Tools/
from px_generate_uorb_topic_files import MsgScope # this is in Tools/

package = package[0]
fastrtpsgen_version = fastrtpsgen_version[0]
try:
    ros2_distro = ros2_distro[0].decode("utf-8")
except AttributeError:
    ros2_distro = ros2_distro[0]
}@
/****************************************************************************
 *
 * Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. Neither the name of the copyright holder 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 HOLDER 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.
 *
 ****************************************************************************/

/*!
 * @@file microRTPS_timesync.h
 * @@brief Adds time sync for the microRTPS bridge
 * @@author Nuno Marques <nuno.marques@@dronesolutions.io>
 * @@author Julian Kent <julian@@auterion.com>
 */

#pragma once

#include <atomic>
#include <functional>
#include <thread>

@[if ros2_distro]@
#include "Timesync_Publisher.h"
#include "Timesync_Subscriber.h"
@[else]@
#include "timesync_Publisher.h"
#include "timesync_Subscriber.h"
@[end if]@

static constexpr double ALPHA_INITIAL = 0.05;
static constexpr double ALPHA_FINAL = 0.003;
static constexpr double BETA_INITIAL = 0.05;
static constexpr double BETA_FINAL = 0.003;
static constexpr int WINDOW_SIZE = 500;
static constexpr int64_t UNKNOWN = 0;
static constexpr int64_t TRIGGER_RESET_THRESHOLD_NS = 100ll * 1000ll * 1000ll;
static constexpr int REQUEST_RESET_COUNTER_THRESHOLD = 5;

class TimeSync {
public:
	TimeSync();
	virtual ~TimeSync();

@[if ros2_distro]@
	void start(const Timesync_Publisher* pub);
@[else]@
	void start(const timesync_Publisher* pub);
@[end if]@

	void reset();
	void stop();

	/**
	 * Get clock monotonic time (raw) in nanoseconds
	 */
	inline int64_t getMonoRawTimeNSec() {
		timespec t;
		clock_gettime(CLOCK_MONOTONIC_RAW, &t);
		return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;
	}

	/**
	 * Get system monotonic time in microseconds
	 */
	inline int64_t getMonoTimeUSec() {
		timespec t;
		clock_gettime(CLOCK_MONOTONIC, &t);
		return (int64_t)(t.tv_sec * 1000000000LL + t.tv_nsec) / 1000LL;
	}

	bool addMeasurement(int64_t local_t1_ns, int64_t remote_t2_ns, int64_t local_t3_ns);

@[if 1.5 <= fastrtpsgen_version <= 1.7]@
@[    if ros2_distro]@
	void processTimesyncMsg(@(package)::msg::dds_::Timesync_* msg);

	@(package)::msg::dds_::Timesync_ newTimesyncMsg();
@[    else]@
	void processTimesyncMsg(timesync_* msg);

	timesync_ newTimesyncMsg();
@[    end if]@
@[else]@
@[    if ros2_distro]@
	void processTimesyncMsg(@(package)::msg::Timesync* msg);

	@(package)::msg::Timesync newTimesyncMsg();
@[    else]@
	void processTimesyncMsg(timesync* msg);

	timesync newTimesyncMsg();
@[    end if]@
@[end if]@

	inline int64_t getOffset() { return _offset_ns.load(); }
	inline void addOffset(uint64_t& timestamp) { timestamp = (timestamp * 1000LL + _offset_ns.load()) / 10000ULL; }
	inline void subtractOffset(uint64_t& timestamp) { timestamp = (timestamp * 1000LL - _offset_ns.load()) / 10000ULL; }

private:
	std::atomic<int64_t> _offset_ns;
	int64_t _skew_ns_per_sync;
	int64_t _num_samples;

	int32_t _request_reset_counter;
	uint8_t _last_msg_seq;
	uint8_t _last_remote_msg_seq;

@[if ros2_distro]@
	Timesync_Publisher _timesync_pub;
	Timesync_Subscriber _timesync_sub;
@[else]@
	timesync_Publisher _timesync_pub;
	timesync_Subscriber _timesync_sub;
@[end if]@

	std::unique_ptr<std::thread> _send_timesync_thread;
	std::atomic<bool> _request_stop{false};

	inline void updateOffset(const uint64_t& offset) { _offset_ns.store(offset, std::memory_order_relaxed); }
};


Making script executable in repo removing chmod from template

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
    now_str=now_str,
))@
@(TEMPLATE(
    'snippet/from_base_image.Dockerfile.em',
    template_packages=template_packages,
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
    base_image=base_image,
))@
MAINTAINER Dirk Thomas dthomas+buildfarm@@osrfoundation.org

# setup environment
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
@[if 'packages' in locals()]@
@[if packages]@

# install packages
RUN apt-get update && apt-get install -y \
    @(' \\\n    '.join(packages))@  \
    && rm -rf /var/lib/apt/lists/*

@[end if]@
@[end if]@

# setup keys
RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys 421C365BD9FF1F717815A3895523BAEEB01FA116

# setup sources.list
RUN echo "deb http://packages.ros.org/ros/@os_name @os_code_name main" > /etc/apt/sources.list.d/ros-latest.list

# install bootstrap tools
ENV ROS_DISTRO @rosdistro_name
RUN apt-get update && apt-get install --no-install-recommends -y \
    python-rosdep \
    python-rosinstall \
    python-vcstools \
    && rm -rf /var/lib/apt/lists/*

# bootstrap rosdep
RUN rosdep init \
    && rosdep update

# install ros packages
RUN apt-get update && apt-get install -y \
    @(' \\\n    '.join(ros_packages))@  \
    && rm -rf /var/lib/apt/lists/*

# setup entrypoint
COPY ./ros_entrypoint.sh /

@[if 'entrypoint_name' in locals()]@
@[if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
ENTRYPOINT ["/@entrypoint_file"]
@[end if]@
@[end if]@
@{
cmds = [
'bash',
]
}@
CMD ["@(' && '.join(cmds))"]

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
    now_str=now_str,
))@
@(TEMPLATE(
    'snippet/from_base_image.Dockerfile.em',
    template_packages=template_packages,
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
    base_image=base_image,
))@
MAINTAINER Dirk Thomas dthomas+buildfarm@@osrfoundation.org

# setup environment
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
@[if 'packages' in locals()]@
@[if packages]@

# install packages
RUN apt-get update && apt-get install -y \
    @(' \\\n    '.join(packages))@  \
    && rm -rf /var/lib/apt/lists/*

@[end if]@
@[end if]@

# setup keys
RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys 421C365BD9FF1F717815A3895523BAEEB01FA116

# setup sources.list
RUN echo "deb http://packages.ros.org/ros/@os_name @os_code_name main" > /etc/apt/sources.list.d/ros-latest.list

# install bootstrap tools
ENV ROS_DISTRO @rosdistro_name
RUN apt-get update && apt-get install --no-install-recommends -y \
    python-rosdep \
    python-rosinstall \
    python-vcstools \
    && rm -rf /var/lib/apt/lists/*

# bootstrap rosdep
RUN rosdep init \
    && rosdep update

# install ros packages
RUN apt-get update && apt-get install -y \
    @(' \\\n    '.join(ros_packages))@  \
    && rm -rf /var/lib/apt/lists/*

# setup entrypoint
COPY ./ros_entrypoint.sh /
RUN chmod +x ./ros_entrypoint.sh

@[if 'entrypoint_name' in locals()]@
@[if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
ENTRYPOINT ["/@entrypoint_file"]
@[end if]@
@[end if]@
@{
cmds = [
'bash',
]
}@
CMD ["@(' && '.join(cmds))"]


thor onboard updated to correct hostname

#!/bin/sh

@[if DEVELSPACE]@
export THOR_SCRIPTS=@(PROJECT_SOURCE_DIR)/scripts
@[else]@
export THOR_SCRIPTS=@(CMAKE_INSTALL_PREFIX)/@(CATKIN_PACKAGE_SHARE_DESTINATION)/scripts
@[end if]@
export THOR_ROOT=$(cd "@(CMAKE_SOURCE_DIR)/.."; pwd)

# set THOR_* environment variables
alias l_vt_hand='. l_vt_hand'
alias r_vt_hand='. r_vt_hand'
alias l_thor_mang_hand='. l_thor_mang_hand'
alias r_thor_mang_hand='. r_thor_mang_hand'

# include THOR_scripts hooks
#if [ -d $THOR_SCRIPTS ]; then
#  . $THOR_SCRIPTS/functions.sh
#  . $THOR_SCRIPTS/robot.sh ""

#  _THOR_include "$THOR_SCRIPTS/setup.d/*.sh"
#  _THOR_include "$THOR_SCRIPTS/$HOSTNAME/setup.d/*.sh"

#  if [ -r "$THOR_SCRIPTS/$HOSTNAME/setup.sh" ]; then
#      echo "Including $THOR_SCRIPTS/$HOSTNAME/setup.sh..." >&2
#      . "$THOR_SCRIPTS/$HOSTNAME/setup.sh"
#  fi
#fi

# export additional ROS_PACKAGE_PATH for indigo
if [ "$ROS_DISTRO" = "indigo" ]; then
    export ROS_BOOST_LIB_DIR_NAME=/usr/lib/x86_64-linux-gnu
    export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$ROS_WORKSPACE/../external
fi

# export some variables
export PATH=$THOR_SCRIPTS/helper:$PATH
export ROS_WORKSPACE=$THOR_ROOT/src
export THOR_MOTION_HOSTNAME="thor-motion"
export THOR_PERCEPTION_HOSTNAME="thor-perception"
export THOR_ONBOARD_HOSTNAME="thor-motion" #need to be thor-motion because on same machine
export THOR_FIELD_HOSTNAME="thor-field"
export ROBOT_HOSTNAMES="thor-motion thor-perception thor-onboard thor-field"
export ROBOT_USER="thor"
export THOR_ROBOT_TYPE="thor_mang_hands"
export LEFT_HAND_TYPE="l_vt_hand"
export RIGHT_HAND_TYPE="r_vt_hand"

# adding ssh keys
if [ -d "$THOR_ROOT/.ssh/" ] && [ "$(ls -A $THOR_ROOT/.ssh/)" ]; then
    #echo "Adding ssh keys from '$THOR_ROOT/.ssh/':"
    for f in $THOR_ROOT/.ssh/*; do
        ssh-add $f
    done
fi

#!/bin/sh

@[if DEVELSPACE]@
export THOR_SCRIPTS=@(PROJECT_SOURCE_DIR)/scripts
@[else]@
export THOR_SCRIPTS=@(CMAKE_INSTALL_PREFIX)/@(CATKIN_PACKAGE_SHARE_DESTINATION)/scripts
@[end if]@
export THOR_ROOT=$(cd "@(CMAKE_SOURCE_DIR)/.."; pwd)

# set THOR_* environment variables
alias l_vt_hand='. l_vt_hand'
alias r_vt_hand='. r_vt_hand'
alias l_thor_mang_hand='. l_thor_mang_hand'
alias r_thor_mang_hand='. r_thor_mang_hand'

# include THOR_scripts hooks
#if [ -d $THOR_SCRIPTS ]; then
#  . $THOR_SCRIPTS/functions.sh
#  . $THOR_SCRIPTS/robot.sh ""

#  _THOR_include "$THOR_SCRIPTS/setup.d/*.sh"
#  _THOR_include "$THOR_SCRIPTS/$HOSTNAME/setup.d/*.sh"

#  if [ -r "$THOR_SCRIPTS/$HOSTNAME/setup.sh" ]; then
#      echo "Including $THOR_SCRIPTS/$HOSTNAME/setup.sh..." >&2
#      . "$THOR_SCRIPTS/$HOSTNAME/setup.sh"
#  fi
#fi

# export additional ROS_PACKAGE_PATH for indigo
if [ "$ROS_DISTRO" = "indigo" ]; then
    export ROS_BOOST_LIB_DIR_NAME=/usr/lib/x86_64-linux-gnu
    export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$ROS_WORKSPACE/../external
fi

# export some variables
export PATH=$THOR_SCRIPTS/helper:$PATH
export ROS_WORKSPACE=$THOR_ROOT/src
export THOR_MOTION_HOSTNAME="thor-motion"
export THOR_PERCEPTION_HOSTNAME="thor-perception"
export THOR_ONBOARD_HOSTNAME="thor-onboard"
export THOR_FIELD_HOSTNAME="thor-field"
export ROBOT_HOSTNAMES="thor-motion thor-perception thor-onboard thor-field"
export ROBOT_USER="thor"
export THOR_ROBOT_TYPE="thor_mang_hands"
export LEFT_HAND_TYPE="l_vt_hand"
export RIGHT_HAND_TYPE="r_vt_hand"

# adding ssh keys
if [ -d "$THOR_ROOT/.ssh/" ] && [ "$(ls -A $THOR_ROOT/.ssh/)" ]; then
    #echo "Adding ssh keys from '$THOR_ROOT/.ssh/':"
    for f in $THOR_ROOT/.ssh/*; do
        ssh-add $f
    done
fi


Fix double free issue when initialization is failed (#423)

Signed-off-by: Donghee Ye <964818a2edbec03f09493583a2972b059526e7eb@samsung.com>

@# Included from rosidl_generator_c/resource/idl__functions.c.em
@{
from ast import literal_eval
from rosidl_parser.definition import AbstractNestedType
from rosidl_parser.definition import AbstractSequence
from rosidl_parser.definition import AbstractString
from rosidl_parser.definition import AbstractWString
from rosidl_parser.definition import Array
from rosidl_parser.definition import BasicType
from rosidl_parser.definition import AbstractGenericString
from rosidl_parser.definition import NamespacedType
from rosidl_generator_c import basetype_to_c
from rosidl_generator_c import idl_structure_type_sequence_to_c_typename
from rosidl_generator_c import idl_structure_type_to_c_include_prefix
from rosidl_generator_c import idl_structure_type_to_c_typename
from rosidl_generator_c import idl_type_to_c
from rosidl_generator_c import interface_path_to_string
from rosidl_generator_c import value_to_c

message_typename = idl_structure_type_to_c_typename(message.structure.namespaced_type)
array_typename = idl_structure_type_sequence_to_c_typename(
    message.structure.namespaced_type)
}@
@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
@# Collect necessary include directives for all members
@{
from collections import OrderedDict
includes = OrderedDict()
for member in message.structure.members:
    if isinstance(member.type, AbstractSequence) and isinstance(member.type.value_type, BasicType):
        member_names = includes.setdefault(
            'rosidl_generator_c/primitives_sequence_functions.h', [])
        member_names.append(member.name)
        continue
    type_ = member.type
    if isinstance(type_, AbstractNestedType):
        type_ = type_.value_type
    if isinstance(type_, AbstractString):
        member_names = includes.setdefault('rosidl_generator_c/string_functions.h', [])
        member_names.append(member.name)
    elif isinstance(type_, AbstractWString):
        member_names = includes.setdefault(
            'rosidl_generator_c/u16string_functions.h', [])
        member_names.append(member.name)
    elif isinstance(type_, NamespacedType):
        include_prefix = idl_structure_type_to_c_include_prefix(type_)
        if include_prefix.endswith('__request'):
            include_prefix = include_prefix[:-9]
        elif include_prefix.endswith('__response'):
            include_prefix = include_prefix[:-10]
        if include_prefix.endswith('__goal'):
            include_prefix = include_prefix[:-6]
        elif include_prefix.endswith('__result'):
            include_prefix = include_prefix[:-8]
        elif include_prefix.endswith('__feedback'):
            include_prefix = include_prefix[:-10]
        member_names = includes.setdefault(
            include_prefix + '__functions.h', [])
        member_names.append(member.name)
}@
@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@
@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
@[if includes]@

// Include directives for member types
@[    for header_file, member_names in includes.items()]@
@[        for member_name in member_names]@
// Member `@(member_name)`
@[        end for]@
@[        if header_file in include_directives]@
// already included above
// @
@[        else]@
@{include_directives.add(header_file)}@
@[        end if]@
#include "@(header_file)"
@[    end for]@
@[end if]@
@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

@#######################################################################
@# message functions
@#######################################################################
bool
@(message_typename)__init(@(message_typename) * msg)
{
  if (!msg) {
    return false;
  }
@{
label_prefix = 'abort_init_'
last_label_index = 0
lines = []
abort_lines = []
for member in message.structure.members:
    lines.append('// ' + member.name)
    if isinstance(member.type, Array):
        if isinstance(member.type.value_type, BasicType):
            if member.has_annotation('default'):
                # set default value for each array element
                for i, default_value in enumerate(literal_eval(member.get_annotation_value('default')['value'])):
                    lines.append('msg->%s[%d] = %s;' % (member.name, i, value_to_c(member.type.value_type, default_value)))
        elif isinstance(member.type.value_type, (AbstractGenericString, NamespacedType)):
            # initialize each array element
            lines.append('for (size_t i = 0; i < %d; ++i) {' % member.type.size)
            lines.append('  if (!%s__init(&msg->%s[i])) {' % (basetype_to_c(member.type.value_type), member.name))
            lines.append('    %s__fini(msg);' % message_typename)
            lines.append('    return false;')
            lines.append('  }')
            lines.append('}')

            if member.has_annotation('default'):
                for i, default_value in enumerate(literal_eval(member.get_annotation_value('default')['value'])):
                    if isinstance(member.type.value_type, AbstractGenericString):
                        lines.append('{')
                        lines.append(
                            '  bool success = %s__assign(&msg->%s[%d], %s);' % \
                            (basetype_to_c(member.type.value_type), member.name, i, value_to_c(member.type.value_type, default_value)))
                        lines.append('  if (!success) {')
                        lines.append('    goto %s%s;' % (label_prefix, last_label_index))
                        abort_lines[0:0] = [
                            '  %s__fini(&msg->%s[%d]);' % (basetype_to_c(member.type.value_type), member.name, i),
                            '%s%d:' % (label_prefix, last_label_index),
                        ]
                        last_label_index += 1
                        lines.append('  }')
                        lines.append('}')

    elif isinstance(member.type, AbstractSequence):
        if not member.has_annotation('default'):
            # initialize the dynamic array with a capacity of zero
            lines.append('if (!%s__init(&msg->%s, 0)) {' % (idl_type_to_c(member.type), member.name))
            lines.append('  %s__fini(msg);' % message_typename)
            lines.append('  return false;')
            lines.append('}')
        else:
            # initialize the dynamic array with the number of default values
            lines.append('{')
            lines.append('  bool success = %s__init(&msg->%s, %d);' % (idl_type_to_c(member.type), member.name, len(literal_eval(member.get_annotation_value('default')['value']))))
            lines.append('  if (!success) {')
            lines.append('    goto %s%d;' % (label_prefix, last_label_index))
            abort_lines[0:0] = [
                '  %s__fini(&msg->%s);' % (idl_type_to_c(member.type), member.name),
                '%s%d:' % (label_prefix, last_label_index),
            ]
            last_label_index += 1
            lines.append('  }')
            lines.append('}')
            # set default value for each array element
            for i, default_value in enumerate(literal_eval(member.get_annotation_value('default')['value'])):
                if isinstance(member.type.value_type, AbstractGenericString):
                    lines.append('{')
                    lines.append(
                        '  bool success = %s__assign(&msg->%s.data[%d], %s);' % \
                        (basetype_to_c(member.type.value_type), member.name, i, value_to_c(member.type.value_type, default_value)))
                    lines.append('  if (!success) {')
                    lines.append('    goto %s%s;' % (label_prefix, last_label_index))
                    abort_lines[0:0] = [
                        '  %s__fini(&msg->%s.data[%d]);' % (basetype_to_c(member.type.value_type), member.name, i),
                        '%s%d:' % (label_prefix, last_label_index),
                    ]
                    last_label_index += 1
                    lines.append('  }')
                    lines.append('}')
                else:
                    lines.append('msg->%s.data[%d] = %s;' % (member.name, i, value_to_c(member.type.value_type, default_value)))

    elif isinstance(member.type, NamespacedType):
            # initialize the sub message
            lines.append('if (!%s__init(&msg->%s)) {' % (basetype_to_c(member.type), member.name))
            lines.append('  %s__fini(msg);' % message_typename)
            lines.append('  return false;')
            lines.append('}')
        # no default value for nested messages yet

    elif isinstance(member.type, AbstractGenericString):
        lines.append('if (!%s__init(&msg->%s)) {' % (basetype_to_c(member.type), member.name))
        lines.append('  %s__fini(msg);' % message_typename)
        lines.append('  return false;')
        lines.append('}')
        if member.has_annotation('default'):
            lines.append('{')
            lines.append(
                '  bool success = %s__assign(&msg->%s, %s);' % (
                basetype_to_c(member.type), member.name,
                value_to_c(member.type, member.get_annotation_value('default')['value'])))
            lines.append('  if (!success) {')
            lines.append('    goto %s%s;' % (label_prefix, last_label_index))
            abort_lines[0:0] = [
                '  %s__fini(&msg->%s);' % (basetype_to_c(member.type), member.name),
                '%s%d:' % (label_prefix, last_label_index),
            ]
            last_label_index += 1
            lines.append('  }')
            lines.append('}')
    elif isinstance(member.type, BasicType):
        if member.has_annotation('default'):
            # set default value of primitive type
            lines.append('msg->%s = %s;' % (member.name, value_to_c(member.type, member.get_annotation_value('default')['value'])))

for line in lines:
    print('  ' + line)
}@
  return true;
@{
if abort_lines:
    # remove lines before the first label since they are unreachable
    while not abort_lines[0].startswith(label_prefix):
        abort_lines.pop(0)
    for line in abort_lines:
        print(line)
    print('  return false;')
}@
}

void
@(message_typename)__fini(@(message_typename) * msg)
{
  if (!msg) {
    return;
  }
@{
lines = []
for member in message.structure.members:
    lines.append('// ' + member.name)
    if isinstance(member.type, Array):
        if isinstance(member.type.value_type, (AbstractGenericString, NamespacedType)):
            lines.append('for (size_t i = 0; i < %d; ++i) {' % member.type.size)
            # initialize each array element
            lines.append('  %s__fini(&msg->%s[i]);' % (basetype_to_c(member.type.value_type), member.name))
            lines.append('}')
    elif isinstance(member.type, AbstractSequence):
        # finalize the dynamic array
        lines.append('%s__fini(&msg->%s);' % (idl_type_to_c(member.type), member.name))
    elif not isinstance(member.type, BasicType):
        # finalize non-array sub messages and strings
        lines.append('%s__fini(&msg->%s);' % (basetype_to_c(member.type), member.name))
for line in lines:
    print('  ' + line)
}@
}

@(message_typename) *
@(message_typename)__create()
{
  @(message_typename) * msg = (@(message_typename) *)malloc(sizeof(@(message_typename)));
  if (!msg) {
    return NULL;
  }
  memset(msg, 0, sizeof(@(message_typename)));
  bool success = @(message_typename)__init(msg);
  if (!success) {
    free(msg);
    return NULL;
  }
  return msg;
}

void
@(message_typename)__destroy(@(message_typename) * msg)
{
  if (msg) {
    @(message_typename)__fini(msg);
  }
  free(msg);
}

@#######################################################################
@# array functions
@#######################################################################
bool
@(array_typename)__init(@(array_typename) * array, size_t size)
{
  if (!array) {
    return false;
  }
  @(message_typename) * data = NULL;
  if (size) {
    data = (@(message_typename) *)calloc(size, sizeof(@(message_typename)));
    if (!data) {
      return false;
    }
    // initialize all array elements
    size_t i;
    for (i = 0; i < size; ++i) {
      bool success = @(message_typename)__init(&data[i]);
      if (!success) {
        break;
      }
    }
    if (i < size) {
      // if initialization failed finalize the already initialized array elements
      for (; i > 0; --i) {
        @(message_typename)__fini(&data[i - 1]);
      }
      free(data);
      return false;
    }
  }
  array->data = data;
  array->size = size;
  array->capacity = size;
  return true;
}

void
@(array_typename)__fini(@(array_typename) * array)
{
  if (!array) {
    return;
  }
  if (array->data) {
    // ensure that data and capacity values are consistent
    assert(array->capacity > 0);
    // finalize all array elements
    for (size_t i = 0; i < array->capacity; ++i) {
      @(message_typename)__fini(&array->data[i]);
    }
    free(array->data);
    array->data = NULL;
    array->size = 0;
    array->capacity = 0;
  } else {
    // ensure that data, size, and capacity values are consistent
    assert(0 == array->size);
    assert(0 == array->capacity);
  }
}

@(array_typename) *
@(array_typename)__create(size_t size)
{
  @(array_typename) * array = (@(array_typename) *)malloc(sizeof(@(array_typename)));
  if (!array) {
    return NULL;
  }
  bool success = @(array_typename)__init(array, size);
  if (!success) {
    free(array);
    return NULL;
  }
  return array;
}

void
@(array_typename)__destroy(@(array_typename) * array)
{
  if (array) {
    @(array_typename)__fini(array);
  }
  free(array);
}

@# Included from rosidl_generator_c/resource/idl__functions.c.em
@{
from ast import literal_eval
from rosidl_parser.definition import AbstractNestedType
from rosidl_parser.definition import AbstractSequence
from rosidl_parser.definition import AbstractString
from rosidl_parser.definition import AbstractWString
from rosidl_parser.definition import Array
from rosidl_parser.definition import BasicType
from rosidl_parser.definition import AbstractGenericString
from rosidl_parser.definition import NamespacedType
from rosidl_generator_c import basetype_to_c
from rosidl_generator_c import idl_structure_type_sequence_to_c_typename
from rosidl_generator_c import idl_structure_type_to_c_include_prefix
from rosidl_generator_c import idl_structure_type_to_c_typename
from rosidl_generator_c import idl_type_to_c
from rosidl_generator_c import interface_path_to_string
from rosidl_generator_c import value_to_c

message_typename = idl_structure_type_to_c_typename(message.structure.namespaced_type)
array_typename = idl_structure_type_sequence_to_c_typename(
    message.structure.namespaced_type)
}@
@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
@# Collect necessary include directives for all members
@{
from collections import OrderedDict
includes = OrderedDict()
for member in message.structure.members:
    if isinstance(member.type, AbstractSequence) and isinstance(member.type.value_type, BasicType):
        member_names = includes.setdefault(
            'rosidl_generator_c/primitives_sequence_functions.h', [])
        member_names.append(member.name)
        continue
    type_ = member.type
    if isinstance(type_, AbstractNestedType):
        type_ = type_.value_type
    if isinstance(type_, AbstractString):
        member_names = includes.setdefault('rosidl_generator_c/string_functions.h', [])
        member_names.append(member.name)
    elif isinstance(type_, AbstractWString):
        member_names = includes.setdefault(
            'rosidl_generator_c/u16string_functions.h', [])
        member_names.append(member.name)
    elif isinstance(type_, NamespacedType):
        include_prefix = idl_structure_type_to_c_include_prefix(type_)
        if include_prefix.endswith('__request'):
            include_prefix = include_prefix[:-9]
        elif include_prefix.endswith('__response'):
            include_prefix = include_prefix[:-10]
        if include_prefix.endswith('__goal'):
            include_prefix = include_prefix[:-6]
        elif include_prefix.endswith('__result'):
            include_prefix = include_prefix[:-8]
        elif include_prefix.endswith('__feedback'):
            include_prefix = include_prefix[:-10]
        member_names = includes.setdefault(
            include_prefix + '__functions.h', [])
        member_names.append(member.name)
}@
@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@
@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
@[if includes]@

// Include directives for member types
@[    for header_file, member_names in includes.items()]@
@[        for member_name in member_names]@
// Member `@(member_name)`
@[        end for]@
@[        if header_file in include_directives]@
// already included above
// @
@[        else]@
@{include_directives.add(header_file)}@
@[        end if]@
#include "@(header_file)"
@[    end for]@
@[end if]@
@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

@#######################################################################
@# message functions
@#######################################################################
bool
@(message_typename)__init(@(message_typename) * msg)
{
  if (!msg) {
    return false;
  }
@{
label_prefix = 'abort_init_'
last_label_index = 0
lines = []
abort_lines = []
for member in message.structure.members:
    lines.append('// ' + member.name)
    if isinstance(member.type, Array):
        if isinstance(member.type.value_type, BasicType):
            if member.has_annotation('default'):
                # set default value for each array element
                for i, default_value in enumerate(literal_eval(member.get_annotation_value('default')['value'])):
                    lines.append('msg->%s[%d] = %s;' % (member.name, i, value_to_c(member.type.value_type, default_value)))
        elif isinstance(member.type.value_type, (AbstractGenericString, NamespacedType)):
            # initialize each array element
            lines.append('for (size_t i = 0; i < %d; ++i) {' % member.type.size)
            lines.append('  if (!%s__init(&msg->%s[i])) {' % (basetype_to_c(member.type.value_type), member.name))
            lines.append('    %s__destroy(msg);' % message_typename)
            lines.append('    return false;')
            lines.append('  }')
            lines.append('}')

            if member.has_annotation('default'):
                for i, default_value in enumerate(literal_eval(member.get_annotation_value('default')['value'])):
                    if isinstance(member.type.value_type, AbstractGenericString):
                        lines.append('{')
                        lines.append(
                            '  bool success = %s__assign(&msg->%s[%d], %s);' % \
                            (basetype_to_c(member.type.value_type), member.name, i, value_to_c(member.type.value_type, default_value)))
                        lines.append('  if (!success) {')
                        lines.append('    goto %s%s;' % (label_prefix, last_label_index))
                        abort_lines[0:0] = [
                            '  %s__fini(&msg->%s[%d]);' % (basetype_to_c(member.type.value_type), member.name, i),
                            '%s%d:' % (label_prefix, last_label_index),
                        ]
                        last_label_index += 1
                        lines.append('  }')
                        lines.append('}')

    elif isinstance(member.type, AbstractSequence):
        if not member.has_annotation('default'):
            # initialize the dynamic array with a capacity of zero
            lines.append('if (!%s__init(&msg->%s, 0)) {' % (idl_type_to_c(member.type), member.name))
            lines.append('  %s__destroy(msg);' % message_typename)
            lines.append('  return false;')
            lines.append('}')
        else:
            # initialize the dynamic array with the number of default values
            lines.append('{')
            lines.append('  bool success = %s__init(&msg->%s, %d);' % (idl_type_to_c(member.type), member.name, len(literal_eval(member.get_annotation_value('default')['value']))))
            lines.append('  if (!success) {')
            lines.append('    goto %s%d;' % (label_prefix, last_label_index))
            abort_lines[0:0] = [
                '  %s__fini(&msg->%s);' % (idl_type_to_c(member.type), member.name),
                '%s%d:' % (label_prefix, last_label_index),
            ]
            last_label_index += 1
            lines.append('  }')
            lines.append('}')
            # set default value for each array element
            for i, default_value in enumerate(literal_eval(member.get_annotation_value('default')['value'])):
                if isinstance(member.type.value_type, AbstractGenericString):
                    lines.append('{')
                    lines.append(
                        '  bool success = %s__assign(&msg->%s.data[%d], %s);' % \
                        (basetype_to_c(member.type.value_type), member.name, i, value_to_c(member.type.value_type, default_value)))
                    lines.append('  if (!success) {')
                    lines.append('    goto %s%s;' % (label_prefix, last_label_index))
                    abort_lines[0:0] = [
                        '  %s__fini(&msg->%s.data[%d]);' % (basetype_to_c(member.type.value_type), member.name, i),
                        '%s%d:' % (label_prefix, last_label_index),
                    ]
                    last_label_index += 1
                    lines.append('  }')
                    lines.append('}')
                else:
                    lines.append('msg->%s.data[%d] = %s;' % (member.name, i, value_to_c(member.type.value_type, default_value)))

    elif isinstance(member.type, NamespacedType):
            # initialize the sub message
            lines.append('if (!%s__init(&msg->%s)) {' % (basetype_to_c(member.type), member.name))
            lines.append('  %s__destroy(msg);' % message_typename)
            lines.append('  return false;')
            lines.append('}')
        # no default value for nested messages yet

    elif isinstance(member.type, AbstractGenericString):
        lines.append('if (!%s__init(&msg->%s)) {' % (basetype_to_c(member.type), member.name))
        lines.append('  %s__destroy(msg);' % message_typename)
        lines.append('  return false;')
        lines.append('}')
        if member.has_annotation('default'):
            lines.append('{')
            lines.append(
                '  bool success = %s__assign(&msg->%s, %s);' % (
                basetype_to_c(member.type), member.name,
                value_to_c(member.type, member.get_annotation_value('default')['value'])))
            lines.append('  if (!success) {')
            lines.append('    goto %s%s;' % (label_prefix, last_label_index))
            abort_lines[0:0] = [
                '  %s__fini(&msg->%s);' % (basetype_to_c(member.type), member.name),
                '%s%d:' % (label_prefix, last_label_index),
            ]
            last_label_index += 1
            lines.append('  }')
            lines.append('}')
    elif isinstance(member.type, BasicType):
        if member.has_annotation('default'):
            # set default value of primitive type
            lines.append('msg->%s = %s;' % (member.name, value_to_c(member.type, member.get_annotation_value('default')['value'])))

for line in lines:
    print('  ' + line)
}@
  return true;
@{
if abort_lines:
    # remove lines before the first label since they are unreachable
    while not abort_lines[0].startswith(label_prefix):
        abort_lines.pop(0)
    for line in abort_lines:
        print(line)
    print('  return false;')
}@
}

void
@(message_typename)__fini(@(message_typename) * msg)
{
  if (!msg) {
    return;
  }
@{
lines = []
for member in message.structure.members:
    lines.append('// ' + member.name)
    if isinstance(member.type, Array):
        if isinstance(member.type.value_type, (AbstractGenericString, NamespacedType)):
            lines.append('for (size_t i = 0; i < %d; ++i) {' % member.type.size)
            # initialize each array element
            lines.append('  %s__fini(&msg->%s[i]);' % (basetype_to_c(member.type.value_type), member.name))
            lines.append('}')
    elif isinstance(member.type, AbstractSequence):
        # finalize the dynamic array
        lines.append('%s__fini(&msg->%s);' % (idl_type_to_c(member.type), member.name))
    elif not isinstance(member.type, BasicType):
        # finalize non-array sub messages and strings
        lines.append('%s__fini(&msg->%s);' % (basetype_to_c(member.type), member.name))
for line in lines:
    print('  ' + line)
}@
}

@(message_typename) *
@(message_typename)__create()
{
  @(message_typename) * msg = (@(message_typename) *)malloc(sizeof(@(message_typename)));
  if (!msg) {
    return NULL;
  }
  memset(msg, 0, sizeof(@(message_typename)));
  bool success = @(message_typename)__init(msg);
  if (!success) {
    free(msg);
    return NULL;
  }
  return msg;
}

void
@(message_typename)__destroy(@(message_typename) * msg)
{
  if (msg) {
    @(message_typename)__fini(msg);
  }
  free(msg);
}

@#######################################################################
@# array functions
@#######################################################################
bool
@(array_typename)__init(@(array_typename) * array, size_t size)
{
  if (!array) {
    return false;
  }
  @(message_typename) * data = NULL;
  if (size) {
    data = (@(message_typename) *)calloc(size, sizeof(@(message_typename)));
    if (!data) {
      return false;
    }
    // initialize all array elements
    size_t i;
    for (i = 0; i < size; ++i) {
      bool success = @(message_typename)__init(&data[i]);
      if (!success) {
        break;
      }
    }
    if (i < size) {
      // if initialization failed finalize the already initialized array elements
      for (; i > 0; --i) {
        @(message_typename)__fini(&data[i - 1]);
      }
      free(data);
      return false;
    }
  }
  array->data = data;
  array->size = size;
  array->capacity = size;
  return true;
}

void
@(array_typename)__fini(@(array_typename) * array)
{
  if (!array) {
    return;
  }
  if (array->data) {
    // ensure that data and capacity values are consistent
    assert(array->capacity > 0);
    // finalize all array elements
    for (size_t i = 0; i < array->capacity; ++i) {
      @(message_typename)__fini(&array->data[i]);
    }
    free(array->data);
    array->data = NULL;
    array->size = 0;
    array->capacity = 0;
  } else {
    // ensure that data, size, and capacity values are consistent
    assert(0 == array->size);
    assert(0 == array->capacity);
  }
}

@(array_typename) *
@(array_typename)__create(size_t size)
{
  @(array_typename) * array = (@(array_typename) *)malloc(sizeof(@(array_typename)));
  if (!array) {
    return NULL;
  }
  bool success = @(array_typename)__init(array, size);
  if (!success) {
    free(array);
    return NULL;
  }
  return array;
}

void
@(array_typename)__destroy(@(array_typename) * array)
{
  if (array) {
    @(array_typename)__fini(array);
  }
  free(array);
}


Delete test_code.em

Delete test_code.em

deffunc int square(number):

    return power number 2

    end


Update subversion plugin to version 2.13.1

<scm class="hudson.scm.SubversionSCM" plugin="subversion@@2.13.1">
  <locations>
    <hudson.scm.SubversionSCM_-ModuleLocation>
      <remote>@ESCAPE(remote)</remote>
@[if local]@
      <local>@ESCAPE(local)</local>
@[end if]@
      <depthOption>infinity</depthOption>
      <ignoreExternalsOption>false</ignoreExternalsOption>
    </hudson.scm.SubversionSCM_-ModuleLocation>
  </locations>
  <excludedRegions/>
  <includedRegions/>
  <excludedUsers/>
  <excludedRevprop/>
  <excludedCommitMessages/>
  <workspaceUpdater class="hudson.scm.subversion.UpdateUpdater"/>
  <ignoreDirPropChanges>false</ignoreDirPropChanges>
  <filterChangelog>false</filterChangelog>
</scm>

<scm class="hudson.scm.SubversionSCM" plugin="subversion@@2.12.1">
  <locations>
    <hudson.scm.SubversionSCM_-ModuleLocation>
      <remote>@ESCAPE(remote)</remote>
@[if local]@
      <local>@ESCAPE(local)</local>
@[end if]@
      <depthOption>infinity</depthOption>
      <ignoreExternalsOption>false</ignoreExternalsOption>
    </hudson.scm.SubversionSCM_-ModuleLocation>
  </locations>
  <excludedRegions/>
  <includedRegions/>
  <excludedUsers/>
  <excludedRevprop/>
  <excludedCommitMessages/>
  <workspaceUpdater class="hudson.scm.subversion.UpdateUpdater"/>
  <ignoreDirPropChanges>false</ignoreDirPropChanges>
  <filterChangelog>false</filterChangelog>
</scm>


More toolbox cleanups

More toolbox cleanups

${
import math

def my_floor(num):
    return int(math.floor(num))

def my_ceil(num):
    return int(math.ceil(num))

# Should we set the line width in the engine to 2.25, and draw non pixel aligned lines?
# Are these already the correct sizes for the XO?

# These sizes need to be sanity checked ...
if theme == "sugar-xo":
    xo = True
    line_width = 2.25       # 2.25
    thick_line_width = 3.5  # 3.5
    subcell_size = 15
    bullet_size = 9.5
    font_height = 24
else: # About 50% smaller
    xo = False
    line_width = 1.125
    thick_line_width = 1.75
    subcell_size = 7
    bullet_size = 5
    font_height = 12

radio_size = my_floor(subcell_size + bullet_size + line_width)
scale_slider_width = my_floor(2 * subcell_size + line_width)
thickness = my_ceil(line_width)

}
style "default"
{
    # Will be overriden in some widgets
    color["focus_line"] = "#FFFFFF"

    bg[NORMAL] = "#808080"
    bg[PRELIGHT] = "#808080"
    bg[ACTIVE] = "#ffffff"
    bg[SELECTED] = "#e7e7e7"

    fg[NORMAL]        = "#000000"
    fg[ACTIVE]        = "#000000"
    fg[SELECTED]      = "#ffffff"
    fg[PRELIGHT]      = "#ffffff"

    text[NORMAL] = "#000000" # "#7f7f7f" 1. need to patch GTK+ to use ACTIVE when focused, 2. what color should this really be?
    text[ACTIVE] = "#000000"
    text[SELECTED] = "#000000"
    text[PRELIGHT] = "#000000"

    base[NORMAL] = "#E6E6E6"
    base[ACTIVE] = "#ffffff"
    base[SELECTED] = "#a6a6a6"
    base[PRELIGHT] = "#ffffff"

    fg[INSENSITIVE] = "#808080"
    text[INSENSITIVE] = "#808080"

    xthickness = $thickness
    ythickness = $thickness

    # A lot of these will probably need to be changed, but this has to
    # be done when the exact sizes are known
    GtkWidget::interior-focus = 0
    GtkWidget::focus-line-width = 1   # This does not do anything really
    GtkWidget::focus-padding = 0
    # 0.05 works good for both the sugar and sugar-xo themes
    GtkWidget::cursor-aspect-ratio = 0.05

    GtkWidget::wide-separators = 0
    GtkWidget::separator-height = $thickness
    GtkWidget::separator-width = $thickness

    GtkRange::activate-slider = 1
    GtkButton::inner-border = { 6, 6, 6, 6 }           # ??

    GtkButton::default-border = { 1, 1, 1, 1 }         # line_width - focus-line-width
    GtkButton::default-outside-border = { 2, 2, 2, 2 } # focus-line-width

    GtkScrolledWindow::scrollbar-spacing = 0

    GtkExpander::expander-size = 24
    GtkExpander::expander-spacing = 2     # XXX

    GtkTreeView::expander-size = 24

    GtkArrow::arrow-size = 1.0

    GtkToolbar::shadow-type = GTK_SHADOW_NONE

    engine "sugar" {
        # Is this correct? Should we make sure it is pixel aligned?
        # 6 pixel for the XO version, and 3 for the "normal" one
        line_width = $line_width
        # 9-10 pixel for the XO version, and 4 for the "normal" one
        thick_line_width = $thick_line_width

        max_radius = $( xo ? 25 : 15)
    }
}

style "window-content"
{
    color["bg_color"] = "#C0C0C0"

    bg[INSENSITIVE] = @bg_color
    base[INSENSITIVE] = @bg_color
}

style "window"
{
    color["bg_color"] = "#C0C0C0"

    bg[NORMAL] = @bg_color
}

style "scrollbar"
{
    GtkRange::slider-width = 16    # ?
    GtkRange::trough-border = 0
    GtkRange::stepper-spacing = 0
    GtkScrollbar::min-slider-length = 30    # ?
    GtkScrollbar::has-forward-stepper = 0
    GtkScrollbar::has-backward-stepper = 0
    GtkScrollbar::has-secondary-forward-stepper = 0
    GtkScrollbar::has-secondary-backward-stepper = 0

    # Hack for mozilla as it does not obey the above style properties ...
    # Really, mozilla should be fixed ...
    GtkRange::stepper-size = 1

    engine "sugar" {
        hint = "scrollbar"
        scrollbar_border = 3
    }
}

style "scale"
{
    GtkWidget::focus-line-width = 0

    # "square" slider (really round of course)
    # Same as indicator-size?
    GtkRange::slider-width = $scale_slider_width
    GtkScale::slider-length = $scale_slider_width
    GtkRange::trough-border = 0
    GtkRange::stepper-spacing = 0
    GtkRange::trough-side-details = 1
}

# hints for the trough sizing hacks
style "hscale" = "scale"
{
    engine "sugar" {
        hint = "hscale"
    }
}

style "vscale" = "scale"
{
    engine "sugar" {
        hint = "vscale"
    }
}

style "spinbutton"
{
    fg[NORMAL]        = "#ffffff"
    engine "sugar" {
        hint = "spinbutton"
    }
}

style "comboboxentry"
{
    # Copied from the "default" style. Part of the workaround for bug #382646.
    text[NORMAL] = "#000000"
    text[ACTIVE] = "#000000"
    text[SELECTED] = "#000000"
    text[PRELIGHT] = "#000000"

    engine "sugar" {
        hint = "comboboxentry"
    }
}

style "frame"
{
    bg[NORMAL] = "#404040"
}

style "notebook"
{
    GtkNotebook::tab-overlap = -2

    xthickness = 0
    ythickness = 0

    bg[ACTIVE] = "#808080"
}

style "toolbutton"
{
    color["focus_line"] = "#000000"

    #bg[NORMAL] = "#404040"
    bg[PRELIGHT] = "#000000"
    bg[ACTIVE] = "#808080"

    fg[NORMAL] = "#FFFFFF"
    fg[ACTIVE] = "#FFFFFF"
    fg[PRELIGHT] = "#ffffff"

    engine "sugar" {
        max_radius = 5.0
    }
}

style "toolbox"
{
    color["bg_color"] = "#404040"

    fg[NORMAL] = "#FFFFFF"
    fg[ACTIVE] = "#FFFFFF"

    bg[NORMAL] = @bg_color
}

style "panel"
{
    bg[NORMAL] = "#C0C0C0"
    fg[NORMAL] = "#000000"
}

style "entry"
{
    # small inner border and a large x/ythickness for entries
    # to reduce the number of hacks needed :-)
    xthickness = $(thickness*3)
    ythickness = $(thickness*3)

    # This tries to get a height of exactly 45 pixel for the entry.
    GtkEntry::inner-border = { $(subcell_size - thickness*3), $(subcell_size - thickness*3),
                               $(my_floor((3*subcell_size - font_height - thickness*3*2)/2)), $(my_ceil((3*subcell_size - font_height - thickness*3*2)/2)) }

    GtkWidget::focus-line-width = 0
}

style "button"
{
    fg[NORMAL]        = "#ffffff"
}

style "combobox"
{
    # Work around GTK+ bug #382646
    text[NORMAL]      = "#FFFFFF"
    text[ACTIVE]      = "#FFFFFF"
    text[PRELIGHT]    = "#ffffff"
}

style "checkbutton"
{
    fg[NORMAL]        = "#000000"
    fg[PRELIGHT]      = "#000000"
    fg[ACTIVE]        = "#000000"

    base[NORMAL]      = "#ffffff"
    base[PRELIGHT]    = "#ffffff"
    base[ACTIVE]      = "#E6E6E6"

    text[PRELIGHT]    = "#5d5d5d"
    text[NORMAL]      = "#5d5d5d"
    text[ACTIVE]      = "#5d5d5d"

    # I won't get the exact sizing, but this should be pretty close
    GtkCheckButton::indicator-size = $radio_size
    GtkCheckButton::indicator-spacing = 3
    GtkWidget::focus-padding = 3
}

style "progressbar"
{
    xthickness = 0
    ythickness = 0

    # Make the bar visible (only until the engine implements it!)
    bg[PRELIGHT] = "#ffffff"
}

style "menu"
{
    color["bg_color"] = "#000000"

    fg[NORMAL]   = "#ffffff"
    fg[PRELIGHT] = "#ffffff"
    bg[NORMAL] = "#808080"

    # The following colors are for the check and radio menu items
    base[NORMAL]      = "#ffffff"
    base[PRELIGHT]    = "#ffffff"
    base[ACTIVE]      = "#E6E6E6"

    text[PRELIGHT]    = "#5d5d5d"
    text[NORMAL]      = "#5d5d5d"
    text[ACTIVE]      = "#5d5d5d"

    GtkMenu::horizontal-padding = 0
    GtkMenu::vertical-padding   = 0

    xthickness = 0
    ythickness = 0
}

style "menuitem"
{
    GtkCheckMenuItem::indicator-size = $radio_size

    bg[PRELIGHT] = "#808080"

    # For check/radio menu items
    text[NORMAL] = "#FFFFFF"
    text[PRELIGHT] = "#FFFFFF"

    GtkMenuItem::horizontal-padding = $line_width
    xthickness = $(my_ceil(line_width * 2))
    ythickness = $thickness
}

style "separatormenuitem"
{
    GtkMenuItem::horizontal-padding = 0
    xthickness = 0
}

class "GtkWidget"      style "default"
class "GtkWindow"      style "window"
class "GtkEventBox"    style "window"
class "GtkNotebook"    style "notebook"
class "GtkEntry"       style "entry"
class "GtkSpinButton"  style "spinbutton"
class "GtkScrollbar"   style "scrollbar"
class "GtkHScale"      style "hscale"
class "GtkVScale"      style "vscale"
class "GtkProgressBar" style "progressbar"

widget_class "<GtkWindow>.*"                style "window-content"

widget_class "*<SugarToolbox>*"             style "toolbox"
widget_class "*<GtkToolButton>*"            style "toolbutton"

widget_class "*<GtkMenu>*"                style "menu"
widget_class "*<GtkMenuItem>*"            style "menuitem"
widget_class "*<GtkSeparatorMenuItem>*"   style "menuitem"

widget_class "*<GtkComboBox>*"         style "combobox"
widget_class "*<GtkComboBoxEntry>*"    style "comboboxentry"
widget_class "*<GtkCombo>*"            style "comboboxentry"
widget_class "*<GtkButton>*"           style "button"
widget_class "*<GtkCheckButton>*"      style "checkbutton"

widget_class "*<SugarPanel>"           style "panel"

widget_class "*<SugarFrameWindow>*"    style "frame"

${
import math

def my_floor(num):
    return int(math.floor(num))

def my_ceil(num):
    return int(math.ceil(num))

# Should we set the line width in the engine to 2.25, and draw non pixel aligned lines?
# Are these already the correct sizes for the XO?

# These sizes need to be sanity checked ...
if theme == "sugar-xo":
    xo = True
    line_width = 2.25       # 2.25
    thick_line_width = 3.5  # 3.5
    subcell_size = 15
    bullet_size = 9.5
    font_height = 24
else: # About 50% smaller
    xo = False
    line_width = 1.125
    thick_line_width = 1.75
    subcell_size = 7
    bullet_size = 5
    font_height = 12

radio_size = my_floor(subcell_size + bullet_size + line_width)
scale_slider_width = my_floor(2 * subcell_size + line_width)
thickness = my_ceil(line_width)

}
style "default"
{
    # Will be overriden in some widgets
    color["focus_line"] = "#FFFFFF"

    bg[NORMAL] = "#808080"
    bg[PRELIGHT] = "#808080"
    bg[ACTIVE] = "#ffffff"
    bg[SELECTED] = "#e7e7e7"

    fg[NORMAL]        = "#000000"
    fg[ACTIVE]        = "#000000"
    fg[SELECTED]      = "#ffffff"
    fg[PRELIGHT]      = "#ffffff"

    text[NORMAL] = "#000000" # "#7f7f7f" 1. need to patch GTK+ to use ACTIVE when focused, 2. what color should this really be?
    text[ACTIVE] = "#000000"
    text[SELECTED] = "#000000"
    text[PRELIGHT] = "#000000"

    base[NORMAL] = "#E6E6E6"
    base[ACTIVE] = "#ffffff"
    base[SELECTED] = "#a6a6a6"
    base[PRELIGHT] = "#ffffff"

    fg[INSENSITIVE] = "#808080"
    text[INSENSITIVE] = "#808080"

    xthickness = $thickness
    ythickness = $thickness

    # A lot of these will probably need to be changed, but this has to
    # be done when the exact sizes are known
    GtkWidget::interior-focus = 0
    GtkWidget::focus-line-width = 1   # This does not do anything really
    GtkWidget::focus-padding = 0
    # 0.05 works good for both the sugar and sugar-xo themes
    GtkWidget::cursor-aspect-ratio = 0.05

    GtkWidget::wide-separators = 0
    GtkWidget::separator-height = $thickness
    GtkWidget::separator-width = $thickness

    GtkRange::activate-slider = 1
    GtkButton::inner-border = { 6, 6, 6, 6 }           # ??

    GtkButton::default-border = { 1, 1, 1, 1 }         # line_width - focus-line-width
    GtkButton::default-outside-border = { 2, 2, 2, 2 } # focus-line-width

    GtkScrolledWindow::scrollbar-spacing = 0

    GtkExpander::expander-size = 24
    GtkExpander::expander-spacing = 2     # XXX

    GtkTreeView::expander-size = 24

    GtkArrow::arrow-size = 1.0

    GtkToolbar::shadow-type = GTK_SHADOW_NONE

    engine "sugar" {
        # Is this correct? Should we make sure it is pixel aligned?
        # 6 pixel for the XO version, and 3 for the "normal" one
        line_width = $line_width
        # 9-10 pixel for the XO version, and 4 for the "normal" one
        thick_line_width = $thick_line_width

        max_radius = $( xo ? 25 : 15)
    }
}

style "window-content"
{
    color["bg_color"] = "#C0C0C0"

    bg[INSENSITIVE] = @bg_color
    base[INSENSITIVE] = @bg_color
}

style "window"
{
    color["bg_color"] = "#C0C0C0"

    bg[NORMAL] = @bg_color
}

style "scrollbar"
{
    GtkRange::slider-width = 16    # ?
    GtkRange::trough-border = 0
    GtkRange::stepper-spacing = 0
    GtkScrollbar::min-slider-length = 30    # ?
    GtkScrollbar::has-forward-stepper = 0
    GtkScrollbar::has-backward-stepper = 0
    GtkScrollbar::has-secondary-forward-stepper = 0
    GtkScrollbar::has-secondary-backward-stepper = 0

    # Hack for mozilla as it does not obey the above style properties ...
    # Really, mozilla should be fixed ...
    GtkRange::stepper-size = 1

    engine "sugar" {
        hint = "scrollbar"
        scrollbar_border = 3
    }
}

style "scale"
{
    GtkWidget::focus-line-width = 0

    # "square" slider (really round of course)
    # Same as indicator-size?
    GtkRange::slider-width = $scale_slider_width
    GtkScale::slider-length = $scale_slider_width
    GtkRange::trough-border = 0
    GtkRange::stepper-spacing = 0
    GtkRange::trough-side-details = 1
}

# hints for the trough sizing hacks
style "hscale" = "scale"
{
    engine "sugar" {
        hint = "hscale"
    }
}

style "vscale" = "scale"
{
    engine "sugar" {
        hint = "vscale"
    }
}

style "spinbutton"
{
    fg[NORMAL]        = "#ffffff"
    engine "sugar" {
        hint = "spinbutton"
    }
}

style "comboboxentry"
{
    # Copied from the "default" style. Part of the workaround for bug #382646.
    text[NORMAL] = "#000000"
    text[ACTIVE] = "#000000"
    text[SELECTED] = "#000000"
    text[PRELIGHT] = "#000000"

    engine "sugar" {
        hint = "comboboxentry"
    }
}

style "frame"
{
    bg[NORMAL] = "#404040"
}

style "notebook"
{
    GtkNotebook::tab-overlap = -2

    xthickness = 0
    ythickness = 0

    bg[ACTIVE] = "#808080"
}

style "toolbutton"
{
    color["focus_line"] = "#000000"

    #bg[NORMAL] = "#404040"
    bg[PRELIGHT] = "#000000"
    bg[ACTIVE] = "#808080"

    fg[NORMAL] = "#FFFFFF"
    fg[ACTIVE] = "#FFFFFF"
    fg[PRELIGHT] = "#ffffff"

    engine "sugar" {
        max_radius = 5.0
    }
}

style "toolbox"
{
    color["bg_color"] = "#404040"

    fg[NORMAL] = "#FFFFFF"
    fg[ACTIVE] = "#FFFFFF"

    bg[NORMAL] = @bg_color
}

style "panel"
{
    bg[NORMAL] = "#C0C0C0"
    fg[NORMAL] = "#000000"
}

style "entry"
{
    # small inner border and a large x/ythickness for entries
    # to reduce the number of hacks needed :-)
    xthickness = $(thickness*3)
    ythickness = $(thickness*3)

    # This tries to get a height of exactly 45 pixel for the entry.
    GtkEntry::inner-border = { $(subcell_size - thickness*3), $(subcell_size - thickness*3),
                               $(my_floor((3*subcell_size - font_height - thickness*3*2)/2)), $(my_ceil((3*subcell_size - font_height - thickness*3*2)/2)) }

    GtkWidget::focus-line-width = 0
}

style "button"
{
    fg[NORMAL]        = "#ffffff"
}

style "combobox"
{
    # Work around GTK+ bug #382646
    text[NORMAL]      = "#FFFFFF"
    text[ACTIVE]      = "#FFFFFF"
    text[PRELIGHT]    = "#ffffff"
}

style "checkbutton"
{
    fg[NORMAL]        = "#000000"
    fg[PRELIGHT]      = "#000000"
    fg[ACTIVE]        = "#000000"

    base[NORMAL]      = "#ffffff"
    base[PRELIGHT]    = "#ffffff"
    base[ACTIVE]      = "#E6E6E6"

    text[PRELIGHT]    = "#5d5d5d"
    text[NORMAL]      = "#5d5d5d"
    text[ACTIVE]      = "#5d5d5d"

    # I won't get the exact sizing, but this should be pretty close
    GtkCheckButton::indicator-size = $radio_size
    GtkCheckButton::indicator-spacing = 3
    GtkWidget::focus-padding = 3
}

style "progressbar"
{
    xthickness = 0
    ythickness = 0

    # Make the bar visible (only until the engine implements it!)
    bg[PRELIGHT] = "#ffffff"
}

style "menu"
{
    color["bg_color"] = "#000000"

    fg[NORMAL]   = "#ffffff"
    fg[PRELIGHT] = "#ffffff"
    bg[NORMAL] = "#808080"

    # The following colors are for the check and radio menu items
    base[NORMAL]      = "#ffffff"
    base[PRELIGHT]    = "#ffffff"
    base[ACTIVE]      = "#E6E6E6"

    text[PRELIGHT]    = "#5d5d5d"
    text[NORMAL]      = "#5d5d5d"
    text[ACTIVE]      = "#5d5d5d"

    GtkMenu::horizontal-padding = 0
    GtkMenu::vertical-padding   = 0

    xthickness = 0
    ythickness = 0
}

style "menuitem"
{
    GtkCheckMenuItem::indicator-size = $radio_size

    bg[PRELIGHT] = "#808080"

    # For check/radio menu items
    text[NORMAL] = "#FFFFFF"
    text[PRELIGHT] = "#FFFFFF"

    GtkMenuItem::horizontal-padding = $line_width
    xthickness = $(my_ceil(line_width * 2))
    ythickness = $thickness
}

style "separatormenuitem"
{
    GtkMenuItem::horizontal-padding = 0
    xthickness = 0
}

class "GtkWidget"      style "default"
class "GtkWindow"      style "window"
class "GtkEventBox"    style "window"
class "GtkNotebook"    style "notebook"
class "GtkEntry"       style "entry"
class "GtkSpinButton"  style "spinbutton"
class "GtkScrollbar"   style "scrollbar"
class "GtkHScale"      style "hscale"
class "GtkVScale"      style "vscale"
class "GtkProgressBar" style "progressbar"

widget_class "<GtkWindow>.*"                style "window-content"

widget_class "*<SugarToolbox>*"             style "toolbox"
widget_class "*<SugarToolbox>.GtkNotebook"  style "toolbox"
widget_class "*<GtkToolButton>*"            style "toolbutton"

widget_class "*<GtkMenu>*"                style "menu"
widget_class "*<GtkMenuItem>*"            style "menuitem"
widget_class "*<GtkSeparatorMenuItem>*"   style "menuitem"

widget_class "*<GtkComboBox>*"         style "combobox"
widget_class "*<GtkComboBoxEntry>*"    style "comboboxentry"
widget_class "*<GtkCombo>*"            style "comboboxentry"
widget_class "*<GtkButton>*"           style "button"
widget_class "*<GtkCheckButton>*"      style "checkbutton"

widget_class "*<SugarPanel>"           style "panel"

widget_class "*<SugarFrameWindow>*"    style "frame"


Before deleting example_tx.ami.em

Before deleting example_tx.ami.em

(@model_name

    (Description "@description")

@{
for (sec_name, sec_key) in [('Reserved_Parameters', 'reserved'), ('Model_Specific', 'model')]:
    print "    (%s" % sec_name
    for param_name in ami_params[sec_key].keys():
        print "        (%s" % param_name
        param = ami_params[sec_key][param_name]
        for (fld_name, fld_key) in [('Usage', 'usage'), ('Type', 'type'), ('Format', 'format'),
                                    ('Default', 'default'), ('Description', 'description'),
                                   ]:
            # Trap the special cases.
            if(fld_name == 'Type'):
                print "            (Type", param_types[param['type']]['ami_type'], ")"
            elif(fld_name == 'Default'):
                if(param['format'] == 'Value'):
                    pass
            elif(fld_name == 'Format'):
                if(param['format'] == 'Value'):
                    print "            (Value", param['default'], ")"
                else:
                    print "            (%s" % param['format'], param['default'], param['min'], param['max'], ")"
            # Execute the default action.
            else:
                print "            (%s" % fld_name, param[fld_key], ")"

        print "        )"
    print "    )"
}
)

(@model_name

    (Description "@description")

    (Reserved_Parameters
@{
for param_name in ami_params['reserved'].keys():
    param = ami_params['reserved'][param_name]
    print "        (%s" % param_name
    print "            (Usage Info)"
    print "            (Type", param_types[param['type']]['ami_type'], ")"
    print "            (Default", param['default'], ")"
    print '            (Description "%s")' % (param['description'],)
    print "        )"
    print
}
    )

    (Model_Specific
@{
for param_name in ami_params['model'].keys():
    param = ami_params['model'][param_name]
    print "        (%s" % param_name
    print "            (Usage", param['usage'], ")"
    print "            (Type", param_types[param['type']]['ami_type'], ")"
    print "            (Default", param['default'], ")"
    print '            (Description "%s")' % (param['description'],)
    print "        )"
    print
}
    )

)