qmi-codegen: refactor, don't use internal packed structs to match TLVs

This is a huge refactor to avoid using internal packed structs to match TLVs
from a raw byte buffer. There are cases where packed structs do not help, for
example when two variable-length fields (like strings) are found in the same
TLV.

Instead of packed structs, we'll read basic types one by one directly from the
raw byte buffer. With this new logic, struct and array variables are no more
than containers of other basic types. Each basic type, implemented as objects
inheriting from a base Variable type, knows how to read/write from/to the
raw buffer. Therefore, reading a struct is just about reading one by one each
of the fields in the struct; and reading an array is just about providing a
loop to read all the array elements one by one.

This greatly simplifies reading basic types like integers, as the implementation
is kept in a single place, regardless of having the integer as the only field
in the TLV or as a field of a struct TLV or as an element of an array TLV.

Strings are treated a bit differently. In string TLVs, the string is to be
considered to be as long as the TLV value itself. In struct TLVs with string
fields, the string is assumed to have a 1-byte length prefix which specifies
the length of the string field within the TLV.
This commit is contained in:
Aleksander Morgado 2012-05-30 12:40:46 +02:00
parent 55e1355400
commit 2a511da7d3
25 changed files with 1622 additions and 1089 deletions

View File

@ -23,7 +23,15 @@ import string
from MessageList import MessageList
import utils
"""
The Client class is responsible for providing the QmiClient-based service
specific client GObject.
"""
class Client:
"""
Constructor
"""
def __init__(self, objects_dictionary):
self.name = None
@ -37,6 +45,9 @@ class Client:
raise ValueError('Missing Client field')
"""
Emits the generic GObject class implementation
"""
def __emit_class(self, hfile, cfile):
translations = { 'underscore' : utils.build_underscore_name(self.name),
'no_prefix_underscore_upper' : string.upper(utils.build_underscore_name(self.name[4:])),
@ -85,6 +96,9 @@ class Client:
cfile.write(string.Template(template).substitute(translations))
"""
Emits the async methods for each known request/response
"""
def __emit_methods(self, hfile, cfile, message_list):
translations = { 'underscore' : utils.build_underscore_name(self.name),
'camelcase' : utils.build_camelcase_name (self.name) }
@ -205,6 +219,10 @@ class Client:
'\n' % input_arg_template)
cfile.write(string.Template(template).substitute(translations))
"""
Emit the service-specific client implementation
"""
def emit(self, hfile, cfile, message_list):
# First, emit common class code
utils.add_separator(hfile, 'CLIENT', self.name);

View File

@ -21,29 +21,35 @@
import string
import utils
from FieldString import FieldString
from FieldStruct import FieldStruct
from FieldStructResult import FieldStructResult
from FieldArray import FieldArray
from FieldBasic import FieldBasic
from FieldResult import FieldResult
from Field import Field
"""
The Container class takes care of handling collections of Input or
Output fields
"""
class Container:
"""
The Container class takes care of handling collections of Input or
Output fields
"""
def __init__(self, prefix, dictionary, common_objects_dictionary):
"""
Constructor
"""
def __init__(self, prefix, container_type, dictionary, common_objects_dictionary):
# The field container prefix usually contains the name of the Message,
# e.g. "Qmi Message Ctl Something"
self.prefix = prefix
# self.name needs to be set by the subclass
if self.name != 'Input' and self.name != 'Output':
raise ValueError('Cannot handle container \'%s\'' % self.name)
# We may have 'Input' or 'Output' containers
if container_type == 'Input':
self.readonly = False
elif container_type == 'Output':
self.readonly = True
else:
raise ValueError('Cannot handle container type \'%s\'' % container_type)
self.name = container_type
# Create the composed full name (prefix + name),
# e.g. "Qmi Message Ctl Something Output Result"
# e.g. "Qmi Message Ctl Something Output"
self.fullname = self.prefix + ' ' + self.name
self.fields = None
@ -80,26 +86,16 @@ class Container:
# Then, really parse each field
for field_dictionary in sorted_dictionary:
if field_dictionary['type'] == 'TLV':
if field_dictionary['format'] == 'array':
self.fields.append(FieldArray(self.fullname, field_dictionary, common_objects_dictionary))
elif field_dictionary['format'] == 'string':
self.fields.append(FieldString(self.fullname, field_dictionary, common_objects_dictionary))
elif field_dictionary['format'] == 'struct':
if field_dictionary['name'] == 'Result':
self.fields.append(FieldStructResult(self.fullname, field_dictionary, common_objects_dictionary))
else:
self.fields.append(FieldStruct(self.fullname, field_dictionary, common_objects_dictionary))
elif field_dictionary['format'] == 'guint8' or \
field_dictionary['format'] == 'guint16' or \
field_dictionary['format'] == 'guint32' or \
field_dictionary['format'] == 'gint8' or \
field_dictionary['format'] == 'gint16' or \
field_dictionary['format'] == 'gint32':
self.fields.append(FieldBasic(self.fullname, field_dictionary, common_objects_dictionary))
if field_dictionary['format'] == 'struct' and \
field_dictionary['name'] == 'Result':
self.fields.append(FieldResult(self.fullname, field_dictionary, common_objects_dictionary))
else:
raise ValueError('Cannot handle TLV format \'%s\'' % field_dictionary['format'])
self.fields.append(Field(self.fullname, field_dictionary, common_objects_dictionary))
"""
Emit enumeration of TLVs in the container
"""
def __emit_tlv_ids_enum(self, f):
if self.fields is None:
return
@ -136,6 +132,9 @@ class Container:
f.write(string.Template(template).substitute(translations))
"""
Emit new container types
"""
def __emit_types(self, hfile, cfile, translations):
# Emit types header
template = (
@ -147,26 +146,29 @@ class Container:
template = (
'\n'
'struct _${camelcase} {\n'
' volatile gint ref_count;\n'
'\n')
' volatile gint ref_count;\n')
cfile.write(string.Template(template).substitute(translations))
if self.fields is not None:
for field in self.fields:
translations['field_type'] = field.field_type
translations['field_variable_name'] = field.variable_name
translations['field_name'] = field.name
template = (
'\n'
' /* ${field_name} */\n'
' gboolean ${field_variable_name}_set;\n'
' ${field_type} ${field_variable_name};\n')
cfile.write(string.Template(template).substitute(translations))
if field.variable is not None:
translations['field_type'] = field.variable.private_format if field.variable.private_format.endswith('*') else field.variable.private_format + ' '
translations['field_variable_name'] = field.variable_name
translations['field_name'] = field.name
template = (
'\n'
' /* ${field_name} */\n'
' gboolean ${field_variable_name}_set;\n'
' ${field_type}${field_variable_name};\n')
cfile.write(string.Template(template).substitute(translations))
cfile.write(
'};\n')
"""
Emit container handling core implementation
"""
def __emit_core(self, hfile, cfile, translations):
# Emit container core header
template = (
@ -215,12 +217,8 @@ class Container:
if self.fields is not None:
for field in self.fields:
if field.dispose is not None:
translations['field_dispose'] = field.dispose
translations['field_variable_name'] = field.variable_name
template = (
' ${field_dispose} (self->${field_variable_name});\n')
cfile.write(string.Template(template).substitute(translations))
if field.variable is not None and field.variable.needs_dispose is True:
field.variable.emit_dispose(cfile, ' ', 'self->' + field.variable_name)
template = (
' g_slice_free (${camelcase}, self);\n'
@ -253,6 +251,9 @@ class Container:
cfile.write(string.Template(template).substitute(translations))
"""
Emit container implementation
"""
def emit(self, hfile, cfile):
translations = { 'name' : self.name,
'camelcase' : utils.build_camelcase_name (self.fullname),

View File

@ -1,38 +0,0 @@
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil -*-
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2012 Lanedo GmbH
#
import string
from Field import Field
from Container import Container
class ContainerOutput(Container):
"""
The ContainerOutput class takes care of handling collections of Output
fields
"""
def __init__(self, prefix, dictionary, common_objects_dictionary):
self.name = 'Output'
self.readonly = True
# Call the parent constructor
Container.__init__(self, prefix, dictionary, common_objects_dictionary)

View File

@ -20,14 +20,18 @@
import string
from Struct import Struct
import utils
import VariableFactory
import TypeFactory
"""
The Field class takes care of handling Input and Output TLVs
"""
class Field:
"""
The Field class takes care of handling Input and Output TLVs
"""
"""
Constructor
"""
def __init__(self, prefix, dictionary, common_objects_dictionary):
# The field prefix, usually the name of the Container,
# e.g. "Qmi Message Ctl Something Output"
@ -38,11 +42,22 @@ class Field:
self.id = dictionary['id']
# Whether the field is to be considered mandatory in the message
self.mandatory = dictionary['mandatory']
# Specific format of the field
self.format = dictionary['format']
self.public_format = dictionary['public-format'] if 'public-format' in dictionary else None
# The type, which must always be "TLV"
self.type = dictionary['type']
# Create the composed full name (prefix + name),
# e.g. "Qmi Message Ctl Something Output Result"
self.fullname = dictionary['fullname'] if 'fullname' in dictionary else self.prefix + ' ' + self.name
# Create our variable object
self.variable = VariableFactory.create_variable(dictionary, self.fullname)
# Create the variable name within the Container
self.variable_name = 'arg_' + string.lower(utils.build_underscore_name(self.name))
# Create the ID enumeration name
self.id_enum_name = string.upper(utils.build_underscore_name(self.prefix + ' TLV ' + self.name))
# Output Fields may have prerequisites
self.prerequisites = []
if 'prerequisites' in dictionary:
@ -61,49 +76,37 @@ class Field:
else:
raise RuntimeError('Common type \'%s\' not found' % prerequisite_dictionary['name'])
# Strings containing how the given type is to be copied and disposed
self.copy = None
self.dispose = None
# The field type to be used in the generated code
self.field_type = None
self.public_field_type = None
# Create the composed full name (prefix + name),
# e.g. "Qmi Message Ctl Something Output Result"
self.fullname = self.prefix + ' ' + self.name
# Create the variable name within the Container
self.variable_name = 'arg_' + string.lower(utils.build_underscore_name(self.name))
# Create the ID enumeration name
self.id_enum_name = string.upper(utils.build_underscore_name(self.prefix + ' TLV ' + self.name))
"""
Emit new types required by this field
"""
def emit_types(self, hfile, cfile):
'''
Subclasses can implement the method to emit the required type
information
'''
pass
if TypeFactory.is_type_emitted(self.fullname) is False:
TypeFactory.set_type_emitted(self.fullname)
self.variable.emit_types(hfile)
"""
Emit the method responsible for getting this TLV from the input/output
container
"""
def emit_getter(self, hfile, cfile):
public_field_type = self.public_field_type if self.public_field_type is not None else self.field_type
translations = { 'name' : self.name,
'variable_name' : self.variable_name,
'public_field_type' : public_field_type,
'public_field_out' : public_field_type if public_field_type.endswith('*') else public_field_type + ' ',
'dispose_warn' : ' Do not free the returned @value, it is owned by @self.' if self.dispose is not None else '',
'public_field_type' : self.variable.public_format,
'public_field_out' : self.variable.public_format if self.variable.public_format.endswith('*') else self.variable.public_format + ' ',
'dispose_warn' : ' Do not free the returned @value, it is owned by @self.' if self.variable.needs_dispose is True else '',
'underscore' : utils.build_underscore_name(self.name),
'prefix_camelcase' : utils.build_camelcase_name(self.prefix),
'prefix_underscore' : utils.build_underscore_name(self.prefix) }
'prefix_underscore' : utils.build_underscore_name(self.prefix),
'const' : 'const ' if self.variable.pass_constant else '' }
# Emit the getter header
template = (
'\n'
'gboolean ${prefix_underscore}_get_${underscore} (\n'
' ${prefix_camelcase} *self,\n'
' ${public_field_out}*value,\n'
' ${const}${public_field_out}*value,\n'
' GError **error);\n')
hfile.write(string.Template(template).substitute(translations))
@ -123,7 +126,7 @@ class Field:
'gboolean\n'
'${prefix_underscore}_get_${underscore} (\n'
' ${prefix_camelcase} *self,\n'
' ${public_field_out}*value,\n'
' ${const}${public_field_out}*value,\n'
' GError **error)\n'
'{\n'
' g_return_val_if_fail (self != NULL, FALSE);\n'
@ -138,29 +141,32 @@ class Field:
'\n'
' /* Just for now, transfer-none always */\n'
' if (value)\n'
' *value = (${public_field_type})self->${variable_name};\n'
' *value = (${public_field_out})(self->${variable_name});\n'
'\n'
' return TRUE;\n'
'}\n')
cfile.write(string.Template(template).substitute(translations))
"""
Emit the method responsible for setting this TLV in the input/output
container
"""
def emit_setter(self, hfile, cfile):
translations = { 'name' : self.name,
'variable_name' : self.variable_name,
'field_type' : self.field_type,
'public_field_type' : self.public_field_type if self.public_field_type is not None else self.field_type,
'field_dispose' : self.dispose + '(self->' + self.variable_name + ');\n' if self.dispose is not None else '',
'field_copy' : self.copy + ' ' if self.copy is not None else '',
'field_type' : self.variable.public_format,
'underscore' : utils.build_underscore_name(self.name),
'prefix_camelcase' : utils.build_camelcase_name(self.prefix),
'prefix_underscore' : utils.build_underscore_name(self.prefix) }
'prefix_underscore' : utils.build_underscore_name(self.prefix),
'const' : 'const ' if self.variable.pass_constant else '' }
# Emit the setter header
template = (
'\n'
'gboolean ${prefix_underscore}_set_${underscore} (\n'
' ${prefix_camelcase} *self,\n'
' ${public_field_type} value,\n'
' ${const}${field_type} value,\n'
' GError **error);\n')
hfile.write(string.Template(template).substitute(translations))
@ -180,27 +186,59 @@ class Field:
'gboolean\n'
'${prefix_underscore}_set_${underscore} (\n'
' ${prefix_camelcase} *self,\n'
' ${public_field_type} value,\n'
' ${const}${field_type} value,\n'
' GError **error)\n'
'{\n'
' g_return_val_if_fail (self != NULL, FALSE);\n'
'\n'
' ${field_dispose}\n'
' self->${variable_name}_set = TRUE;\n'
' self->${variable_name} = (${field_type})${field_copy}(value);\n'
'\n'
' return TRUE;\n'
'}\n'
'\n')
' self->${variable_name}_set = TRUE;\n')
cfile.write(string.Template(template).substitute(translations))
self.variable.emit_dispose(cfile, ' ', 'self->' + self.variable_name)
self.variable.emit_copy(cfile, ' ', 'value', 'self->' + self.variable_name)
cfile.write(
'\n'
' return TRUE;\n'
'}\n')
"""
Emit the code responsible for adding the TLV to the QMI message
"""
def emit_input_tlv_add(self, f, line_prefix):
'''
Subclasses can implement the method to emit the required TLV adding
'''
pass
translations = { 'name' : self.name,
'tlv_id' : self.id_enum_name,
'variable_name' : self.variable_name,
'lp' : line_prefix }
template = (
'${lp}guint8 buffer[1024];\n'
'${lp}guint16 buffer_len = 1024;\n'
'${lp}guint8 *buffer_aux = buffer;\n'
'\n')
f.write(string.Template(template).substitute(translations))
# Now, write the contents of the variable into the buffer
self.variable.emit_buffer_write(f, line_prefix, 'input->' + self.variable_name, 'buffer_aux', 'buffer_len')
template = (
'\n'
'${lp}if (!qmi_message_tlv_add (self,\n'
'${lp} (guint8)${tlv_id},\n'
'${lp} (1024 - buffer_len),\n'
'${lp} buffer,\n'
'${lp} error)) {\n'
'${lp} g_prefix_error (error, \"Couldn\'t set the ${name} TLV: \");\n'
'${lp} qmi_message_unref (self);\n'
'${lp} return NULL;\n'
'${lp}}\n')
f.write(string.Template(template).substitute(translations))
"""
Emit the code responsible for checking prerequisites in output TLVs
"""
def emit_output_prerequisite_check(self, f, line_prefix):
if self.prerequisites == []:
f.write('%s/* No Prerequisites for field */\n' % line_prefix)
@ -218,21 +256,98 @@ class Field:
f.write(string.Template(template).substitute(translations))
"""
Emit the code responsible for retrieving the TLV from the QMI message
"""
def emit_output_tlv_get(self, f, line_prefix):
'''
Subclasses can implement the method to emit the required TLV retrieval
'''
pass
translations = { 'name' : self.name,
'container_underscore' : utils.build_underscore_name (self.prefix),
'tlv_id' : self.id_enum_name,
'variable_name' : self.variable_name,
'lp' : line_prefix,
'error' : 'error' if self.mandatory == 'yes' else 'NULL'}
def emit_output_tlv_get_printable(self, f):
translations = { 'underscore' : utils.build_underscore_name (self.fullname) }
template = (
'${lp}guint8 *buffer;\n'
'${lp}guint16 buffer_len;\n'
'\n'
'${lp}if (qmi_message_tlv_get (message,\n'
'${lp} ${tlv_id},\n'
'${lp} &buffer_len,\n'
'${lp} &buffer,\n'
'${lp} ${error})) {\n'
'${lp} self->${variable_name}_set = TRUE;\n'
'\n')
f.write(string.Template(template).substitute(translations))
# Now, read the contents of the buffer into the variable
self.variable.emit_buffer_read(f, line_prefix + ' ', 'self->' + self.variable_name, 'buffer', 'buffer_len')
template = (
'\n'
'${lp} /* The remaining size of the buffer needs to be 0 if we successfully read the TLV */\n'
'${lp} if (buffer_len > 0) {\n'
'${lp} g_warning ("Left \'%u\' bytes unread when getting the \'${name}\' TLV", buffer_len);\n'
'${lp} }\n')
if self.mandatory == 'yes':
template += (
'${lp}} else {\n'
'${lp} g_prefix_error (error, \"Couldn\'t get the ${name} TLV: \");\n'
'${lp} ${container_underscore}_unref (self);\n'
'${lp} return NULL;\n'
'${lp}}\n')
else:
template += (
'${lp}}\n')
f.write(string.Template(template).substitute(translations))
"""
Emit the method responsible for creating a printable representation of the TLV
"""
def emit_output_tlv_get_printable(self, f):
if TypeFactory.is_get_printable_emitted(self.fullname):
return
TypeFactory.set_get_printable_emitted(self.fullname)
translations = { 'name' : self.name,
'tlv_id' : self.id_enum_name,
'underscore' : utils.build_underscore_name (self.fullname) }
template = (
'\n'
'static gchar *\n'
'${underscore}_get_printable (\n'
' QmiMessage *self,\n'
' QmiMessage *message,\n'
' const gchar *line_prefix)\n'
'{\n'
' guint8 *buffer;\n'
' guint16 buffer_len;\n'
'\n'
' if (qmi_message_tlv_get (message,\n'
' ${tlv_id},\n'
' &buffer_len,\n'
' &buffer,\n'
' NULL)) {\n'
' GString *printable;\n'
'\n'
' printable = g_string_new ("");\n')
f.write(string.Template(template).substitute(translations))
# Now, read the contents of the buffer into the printable representation
self.variable.emit_get_printable(f, ' ', 'printable', 'buffer', 'buffer_len')
template = (
'\n'
' /* The remaining size of the buffer needs to be 0 if we successfully read the TLV */\n'
' if (buffer_len > 0) {\n'
' g_warning ("Left \'%u\' bytes unread when getting the \'${name}\' TLV as printable", buffer_len);\n'
' }\n'
'\n'
' return g_string_free (printable, FALSE);\n'
' }\n'
'\n'
' return NULL;\n'
'}\n')
f.write(string.Template(template).substitute(translations))

View File

@ -1,185 +0,0 @@
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil -*-
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2012 Lanedo GmbH
#
import string
import utils
from Struct import Struct
from Field import Field
class FieldArray(Field):
"""
The FieldArray class takes care of handling 'array' format based
Input and Output TLVs
"""
def __init__(self, prefix, dictionary, common_objects_dictionary):
# Call the parent constructor
Field.__init__(self, prefix, dictionary, common_objects_dictionary)
if dictionary['array-element']['format'] != 'struct':
raise ValueError('Cannot handle arrays of format \'%s\'' % dictionary['array-element']['format'])
# Set a struct as content
self.array_element = Struct(utils.build_camelcase_name (self.fullname +
' ' +
dictionary['array-element']['name']),
dictionary['array-element']['contents'])
# We'll use standard GArrays
self.field_type = 'GArray *';
# The array needs to get disposed
self.dispose = 'g_array_unref'
def emit_types(self, hfile, cfile):
'''
Emit the type for the struct used as array element
'''
self.array_element.emit(hfile)
self.array_element.emit_packed(cfile)
def emit_input_tlv_add(self, cfile, line_prefix):
# TODO
raise ValueError('Array as input not implemented yet')
def emit_output_tlv_get(self, f, line_prefix):
translations = { 'name' : self.name,
'container_underscore' : utils.build_underscore_name (self.prefix),
'array_element_type' : self.array_element.name,
'tlv_id' : self.id_enum_name,
'variable_name' : self.variable_name,
'lp' : line_prefix,
'error' : 'error' if self.mandatory == 'yes' else 'NULL'}
template = (
'\n'
'${lp}guint i;\n'
'${lp}guint8 buffer[1024];\n'
'${lp}guint16 buffer_len = 1024;\n'
'${lp}${array_element_type}Packed *item;\n'
'\n'
'${lp}if (qmi_message_tlv_get_varlen (message,\n'
'${lp} ${tlv_id},\n'
'${lp} &buffer_len,\n'
'${lp} buffer,\n'
'${lp} ${error})) {\n'
'${lp} guint8 nitems = buffer[0];\n'
'\n'
'${lp} self->${variable_name}_set = TRUE;\n'
'${lp} self->${variable_name} = g_array_sized_new (FALSE, FALSE, sizeof (${array_element_type}), nitems);\n'
'${lp} for (i = 0, item = (${array_element_type}Packed *)&buffer[1]; i < nitems; i++, item++) {\n'
'${lp} ${array_element_type} tmp;\n'
'\n')
f.write(string.Template(template).substitute(translations))
for struct_field in self.array_element.members:
f.write('%s %s;\n' % (line_prefix,
utils.he_from_le ('item->' + utils.build_underscore_name(struct_field['name']),
'tmp.' + utils.build_underscore_name(struct_field['name']),
struct_field['format'])))
template = (
'${lp} g_array_insert_val (self->${variable_name}, i, tmp);\n'
'${lp} }\n')
if self.mandatory == 'yes':
template += (
'${lp}} else {\n'
'${lp} g_prefix_error (error, \"Couldn\'t get the ${name} TLV: \");\n'
'${lp} ${container_underscore}_unref (self);\n'
'${lp} return NULL;\n'
'${lp}}\n')
else:
template += (
'${lp}}\n')
f.write(string.Template(template).substitute(translations))
def emit_output_tlv_get_printable(self, f):
translations = { 'underscore' : utils.build_underscore_name (self.fullname),
'array_element_type' : self.array_element.name,
'tlv_id' : self.id_enum_name }
template = (
'\n'
'static gchar *\n'
'${underscore}_get_printable (\n'
' QmiMessage *self,\n'
' const gchar *line_prefix)\n'
'{\n'
' GString *printable;\n'
' guint i;\n'
' guint8 buffer[1024];\n'
' guint16 buffer_len = 1024;\n'
' ${array_element_type}Packed *item;\n'
'\n'
' printable = g_string_new ("");\n'
' if (qmi_message_tlv_get_varlen (self,\n'
' ${tlv_id},\n'
' &buffer_len,\n'
' buffer,\n'
' NULL)) {\n'
' guint8 nitems = buffer[0];\n'
'\n'
' for (i = 0, item = (${array_element_type}Packed *)&buffer[1]; i < nitems; i++, item++) {\n'
' ${array_element_type} tmp;\n'
'\n'
' g_string_append_printf (printable,\n'
' "\\n"\n'
' "%s [#%u]",\n'
' line_prefix, i);\n'
'\n')
f.write(string.Template(template).substitute(translations))
for struct_field in self.array_element.members:
translations['name_struct_field'] = struct_field['name']
translations['underscore_struct_field'] = utils.build_underscore_name(struct_field['name'])
translations['endianfix'] = utils.he_from_le ('item->' + utils.build_underscore_name(struct_field['name']),
'tmp.' + utils.build_underscore_name(struct_field['name']),
struct_field['format'])
template = (
' ${endianfix};\n')
if struct_field['format'] == 'guint8' or \
struct_field['format'] == 'guint16' or \
struct_field['format'] == 'guin32':
template += (
' g_string_append_printf (printable,\n'
' "\\n"\n'
' "%s [${name_struct_field} = %u] ",\n'
' line_prefix,\n'
' (guint)tmp.${underscore_struct_field});\n')
else:
template += (
' g_string_append_printf (printable,\n'
' "\\n"'
' "%s [${name_struct_field} = %d] ",\n'
' line_prefix,\n'
' (gint)tmp.${underscore_struct_field});\n')
f.write(string.Template(template).substitute(translations))
f.write(
' }\n'
' }\n'
'\n'
' return g_string_free (printable, FALSE);\n'
'}\n')

View File

@ -1,137 +0,0 @@
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2012 Lanedo GmbH
#
import string
import utils
from Field import Field
class FieldBasic(Field):
"""
The FieldBasic class takes care of handling Input and Output TLVs based
on basic types (e.g. integers)
"""
def __init__(self, prefix, dictionary, common_objects_dictionary):
# Call the parent constructor
Field.__init__(self, prefix, dictionary, common_objects_dictionary)
# The field type to be used in the generated code is the same as the one
# given in the database
self.field_type = self.format;
self.public_field_type = self.public_format;
def emit_input_tlv_add(self, cfile, line_prefix):
translations = { 'name' : self.name,
'tlv_id' : self.id_enum_name,
'field_type' : self.field_type,
'variable_name' : self.variable_name,
'set_variable' : utils.le_from_he ('input->' + self.variable_name, 'tmp', self.field_type),
'lp' : line_prefix }
template = (
'${lp}${field_type} tmp;\n'
'\n'
'${lp}${set_variable};\n'
'\n'
'${lp}if (!qmi_message_tlv_add (self,\n'
'${lp} (guint8)${tlv_id},\n'
'${lp} sizeof (tmp),\n'
'${lp} &tmp,\n'
'${lp} error)) {\n'
'${lp} g_prefix_error (error, \"Couldn\'t set the ${name} TLV: \");\n'
'${lp} qmi_message_unref (self);\n'
'${lp} return NULL;\n'
'${lp}}\n')
cfile.write(string.Template(template).substitute(translations))
def emit_output_tlv_get(self, cfile, line_prefix):
translations = { 'name' : self.name,
'container_underscore' : utils.build_underscore_name (self.prefix),
'tlv_id' : self.id_enum_name,
'variable_name' : self.variable_name,
'lp' : line_prefix,
'error' : 'error' if self.mandatory == 'yes' else 'NULL'}
template = (
'${lp}if (qmi_message_tlv_get (message,\n'
'${lp} ${tlv_id},\n'
'${lp} sizeof (self->${variable_name}),\n'
'${lp} &self->${variable_name},\n'
'${lp} ${error})) {\n'
'${lp} self->${variable_name}_set = TRUE;\n')
cfile.write(string.Template(template).substitute(translations))
cfile.write('%s %s;\n' % (line_prefix,
utils.le_from_he ('self->' + self.variable_name,
'self->' + self.variable_name,
self.field_type)))
if self.mandatory == 'yes':
template = (
'${lp}} else {\n'
'${lp} g_prefix_error (error, \"Couldn\'t get the ${name} TLV: \");\n'
'${lp} ${container_underscore}_unref (self);\n'
'${lp} return NULL;\n'
'${lp}}\n')
else:
template = (
'${lp}}\n')
cfile.write(string.Template(template).substitute(translations))
def emit_output_tlv_get_printable(self, f):
translations = { 'underscore' : utils.build_underscore_name (self.fullname),
'field_type' : self.field_type,
'tlv_id' : self.id_enum_name }
template = (
'\n'
'static gchar *\n'
'${underscore}_get_printable (\n'
' QmiMessage *self,\n'
' const gchar *line_prefix)\n'
'{\n'
' ${field_type} tmp;\n'
' gchar *printable;\n'
'\n'
' g_assert (qmi_message_tlv_get (self,\n'
' ${tlv_id},\n'
' sizeof (tmp),\n'
' &tmp,\n'
' NULL));\n')
template += (' %s;\n' % (utils.le_from_he('tmp', 'tmp', self.field_type)))
if self.format == 'guint8' or \
self.format == 'guint16' or \
self.format == 'guin32':
template += (
' printable = g_strdup_printf ("%u", (guint)tmp);\n')
else:
template += (
' printable = g_strdup_printf ("%d", (gint)tmp);\n')
template += (
'\n'
' return printable;\n'
'}\n')
f.write(string.Template(template).substitute(translations))

View File

@ -21,19 +21,30 @@
import string
import utils
from Struct import Struct
from FieldStruct import FieldStruct
import TypeFactory
from Field import Field
class FieldStructResult(FieldStruct):
"""
The FieldResult class takes care of handling the common 'Result' TLV
"""
"""
The FieldResult class takes care of handling the common 'Result' TLV
"""
class FieldResult(Field):
"""
Emit the types required to the source file (they will not be exposed in the
interface)
"""
def emit_types(self, hfile, cfile):
# Emit both packed/unpacked types to the SOURCE file (not public)
self.contents.emit_packed(cfile)
self.contents.emit(cfile)
if TypeFactory.is_type_emitted(self.fullname) is False:
TypeFactory.set_type_emitted(self.fullname)
self.variable.emit_types(cfile)
"""
Emit the method responsible for getting the Result TLV contents. This
special TLV will have its own getter implementation, as we want to have
proper GErrors built from the QMI result status/code.
"""
def emit_getter(self, hfile, cfile):
translations = { 'variable_name' : self.variable_name,
'prefix_camelcase' : utils.build_camelcase_name(self.prefix),
@ -91,14 +102,20 @@ class FieldStructResult(FieldStruct):
'}\n')
cfile.write(string.Template(template).substitute(translations))
def emit_output_tlv_get_printable(self, f):
translations = { 'name' : self.name,
'underscore' : utils.build_underscore_name (self.fullname),
'container_underscore' : utils.build_underscore_name (self.prefix),
'field_type' : self.field_type,
'tlv_id' : self.id_enum_name,
'variable_name' : self.variable_name }
"""
Emit the method responsible for getting a printable representation of this
TLV field.
"""
def emit_output_tlv_get_printable(self, f):
if TypeFactory.is_get_printable_emitted(self.fullname):
return
TypeFactory.set_get_printable_emitted(self.fullname)
translations = { 'name' : self.name,
'tlv_id' : self.id_enum_name,
'underscore' : utils.build_underscore_name (self.fullname) }
template = (
'\n'
'static gchar *\n'
@ -106,34 +123,40 @@ class FieldStructResult(FieldStruct):
' QmiMessage *self,\n'
' const gchar *line_prefix)\n'
'{\n'
' GString *printable;\n'
' ${field_type}Packed tmp;\n'
' guint8 *buffer;\n'
' guint16 buffer_len;\n'
'\n'
' printable = g_string_new ("");\n'
' g_assert (qmi_message_tlv_get (self,\n'
' ${tlv_id},\n'
' sizeof (tmp),\n'
' &tmp,\n'
' NULL));\n')
f.write(string.Template(template).substitute(translations))
for struct_field in self.contents.members:
translations['name_struct_field'] = struct_field['name']
translations['underscore_struct_field'] = utils.build_underscore_name(struct_field['name'])
translations['endianfix'] = utils.he_from_le ('tmp.' + utils.build_underscore_name(struct_field['name']),
'tmp.' + utils.build_underscore_name(struct_field['name']),
struct_field['format'])
template = (
' ${endianfix};')
f.write(
' if (tmp.error_status == QMI_STATUS_SUCCESS)\n'
' g_string_append (printable,\n'
' "SUCCESS");\n'
' else\n'
' g_string_append_printf (printable,\n'
' "FAILURE: %s",\n'
' qmi_protocol_error_get_string ((QmiProtocolError) tmp.error_code));\n'
' if (qmi_message_tlv_get (self,\n'
' ${tlv_id},\n'
' &buffer_len,\n'
' &buffer,\n'
' NULL)) {\n'
' GString *printable;\n'
' guint16 error_status;\n'
' guint16 error_code;\n'
'\n'
' return g_string_free (printable, FALSE);\n'
' printable = g_string_new ("");\n'
' qmi_utils_read_guint16_from_buffer (\n'
' &buffer,\n'
' &buffer_len,\n'
' &error_status);\n'
' qmi_utils_read_guint16_from_buffer (\n'
' &buffer,\n'
' &buffer_len,\n'
' &error_code);\n'
'\n'
' g_warn_if_fail (buffer_len == 0);\n'
'\n'
' if (error_status == QMI_STATUS_SUCCESS)\n'
' g_string_append (printable, "SUCCESS");\n'
' else\n'
' g_string_append_printf (printable,\n'
' "FAILURE: %s",\n'
' qmi_protocol_error_get_string ((QmiProtocolError) error_code));\n'
'\n'
' return g_string_free (printable, FALSE);\n'
' }\n'
'\n'
' return NULL;\n'
'}\n')
f.write(string.Template(template).substitute(translations))

View File

@ -1,115 +0,0 @@
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2012 Lanedo GmbH
#
import string
import utils
from Field import Field
class FieldString(Field):
"""
The FieldString class takes care of handling 'string' format based
Input and Output TLVs
"""
def __init__(self, prefix, dictionary, common_objects_dictionary):
# Call the parent constructor
Field.__init__(self, prefix, dictionary, common_objects_dictionary)
# The field type will be the given string name
self.field_type = 'gchar *'
self.public_field_type = 'const gchar *'
# The string needs to get disposed
self.dispose = 'g_free'
# The string needs to be copied when set
self.copy = 'g_strdup'
def emit_input_tlv_add(self, cfile, line_prefix):
translations = { 'name' : self.name,
'tlv_id' : self.id_enum_name,
'variable_name' : self.variable_name,
'lp' : line_prefix }
template = (
'${lp}if (!qmi_message_tlv_add (self,\n'
'${lp} (guint8)${tlv_id},\n'
'${lp} strlen (input->${variable_name}) + 1,\n'
'${lp} input->${variable_name},\n'
'${lp} error)) {\n'
'${lp} g_prefix_error (error, \"Couldn\'t set the \'${name}\' TLV: \");\n'
'${lp} qmi_message_unref (self);\n'
'${lp} return NULL;\n'
'${lp}}\n')
cfile.write(string.Template(template).substitute(translations))
def emit_output_tlv_get(self, f, line_prefix):
translations = { 'name' : self.name,
'container_underscore' : utils.build_underscore_name (self.prefix),
'field_type' : self.field_type,
'tlv_id' : self.id_enum_name,
'variable_name' : self.variable_name,
'lp' : line_prefix,
'error' : 'error' if self.mandatory == 'yes' else 'NULL'}
template = (
'${lp}self->${variable_name} = qmi_message_tlv_get_string (message,\n'
'${lp} ${tlv_id},\n'
'${lp} ${error});\n'
'${lp}if (self->${variable_name}) {\n'
'${lp} self->${variable_name}_set = TRUE;\n')
if self.mandatory == 'yes':
template += (
'${lp}} else {\n'
'${lp} g_prefix_error (error, \"Couldn\'t get the ${name} TLV: \");\n'
'${lp} ${container_underscore}_unref (self);\n'
'${lp} return NULL;\n'
'${lp}}\n')
else:
template += (
'${lp}}\n')
f.write(string.Template(template).substitute(translations))
def emit_output_tlv_get_printable(self, f):
translations = { 'underscore' : utils.build_underscore_name (self.fullname),
'tlv_id' : self.id_enum_name }
template = (
'\n'
'static gchar *\n'
'${underscore}_get_printable (\n'
' QmiMessage *self,\n'
' const gchar *line_prefix)\n'
'{\n'
' gchar *str;\n'
' gchar *printable;\n'
'\n'
' str = qmi_message_tlv_get_string (self,\n'
' ${tlv_id},\n'
' NULL);\n'
' g_assert (str != NULL);\n'
' printable = g_strdup_printf ("\'%s\'", str);\n'
' g_free (str);\n'
'\n'
' return printable;\n'
'}\n')
f.write(string.Template(template).substitute(translations))

View File

@ -1,179 +0,0 @@
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2012 Lanedo GmbH
#
import string
import utils
from Struct import Struct
from Field import Field
class FieldStruct(Field):
"""
The FieldStruct class takes care of handling 'struct' format based
Input and Output TLVs
"""
def __init__(self, prefix, dictionary, common_objects_dictionary):
# Call the parent constructor
Field.__init__(self, prefix, dictionary, common_objects_dictionary)
# The field type will be the given struct name
self.field_type = utils.build_camelcase_name(self.fullname)
# Set a struct as content
self.contents = Struct(self.field_type,
dictionary['contents'])
def emit_types(self, hfile, cfile):
'''
Emit the Struct type info
'''
self.contents.emit_packed(cfile)
self.contents.emit(hfile)
def emit_input_tlv_add(self, cfile, line_prefix):
translations = { 'name' : self.name,
'tlv_id' : self.id_enum_name,
'field_type' : self.field_type,
'variable_name' : self.variable_name,
'lp' : line_prefix }
template = (
'${lp}${field_type}Packed tmp;\n'
'\n')
cfile.write(string.Template(template).substitute(translations))
# uint32 and uint16 fields need to be converted to host-endianness
for struct_field in self.contents.members:
cfile.write('%s%s;\n' % (line_prefix,
utils.le_from_he ('input->' + self.variable_name + '.' + utils.build_underscore_name(struct_field['name']),
'tmp.' + utils.build_underscore_name(struct_field['name']),
struct_field['format'])))
template = (
'\n'
'${lp}if (!qmi_message_tlv_add (self,\n'
'${lp} (guint8)${tlv_id},\n'
'${lp} sizeof (tmp),\n'
'${lp} &tmp,\n'
'${lp} error)) {\n'
'${lp} g_prefix_error (error, \"Couldn\'t set the ${name} TLV: \");\n'
'${lp} qmi_message_unref (self);\n'
'${lp} return NULL;\n'
'${lp}}\n')
cfile.write(string.Template(template).substitute(translations))
def emit_output_tlv_get(self, f, line_prefix):
translations = { 'name' : self.name,
'container_underscore' : utils.build_underscore_name (self.prefix),
'field_type' : self.field_type,
'tlv_id' : self.id_enum_name,
'variable_name' : self.variable_name,
'lp' : line_prefix,
'error' : 'error' if self.mandatory == 'yes' else 'NULL'}
template = (
'${lp}${field_type}Packed tmp;\n'
'\n'
'${lp}if (qmi_message_tlv_get (message,\n'
'${lp} ${tlv_id},\n'
'${lp} sizeof (tmp),\n'
'${lp} &tmp,\n'
'${lp} ${error})) {\n'
'${lp} self->${variable_name}_set = TRUE;\n')
f.write(string.Template(template).substitute(translations))
for struct_field in self.contents.members:
f.write('%s %s;\n' % (line_prefix,
utils.he_from_le ('tmp.' + utils.build_underscore_name(struct_field['name']),
'self->' + self.variable_name + '.' + utils.build_underscore_name(struct_field['name']),
struct_field['format'])))
if self.mandatory == 'yes':
template = (
'${lp}} else {\n'
'${lp} g_prefix_error (error, \"Couldn\'t get the ${name} TLV: \");\n'
'${lp} ${container_underscore}_unref (self);\n'
'${lp} return NULL;\n'
'${lp}}\n')
else:
template = (
'${lp}}\n')
f.write(string.Template(template).substitute(translations))
def emit_output_tlv_get_printable(self, f):
translations = { 'name' : self.name,
'underscore' : utils.build_underscore_name (self.fullname),
'container_underscore' : utils.build_underscore_name (self.prefix),
'field_type' : self.field_type,
'tlv_id' : self.id_enum_name,
'variable_name' : self.variable_name }
template = (
'\n'
'static gchar *\n'
'${underscore}_get_printable (\n'
' QmiMessage *self,\n'
' const gchar *line_prefix)\n'
'{\n'
' GString *printable;\n'
' ${field_type}Packed tmp;\n'
'\n'
' printable = g_string_new ("");\n'
' g_assert (qmi_message_tlv_get (self,\n'
' ${tlv_id},\n'
' sizeof (tmp),\n'
' &tmp,\n'
' NULL));\n')
f.write(string.Template(template).substitute(translations))
first = False
for struct_field in self.contents.members:
translations['name_struct_field'] = struct_field['name']
translations['underscore_struct_field'] = utils.build_underscore_name(struct_field['name'])
translations['endianfix'] = utils.he_from_le ('tmp.' + utils.build_underscore_name(struct_field['name']),
'tmp.' + utils.build_underscore_name(struct_field['name']),
struct_field['format'])
template = (
' ${endianfix};'
' g_string_append_printf (printable,\n')
if struct_field['format'] == 'guint8' or \
struct_field['format'] == 'guint16' or \
struct_field['format'] == 'guin32':
template += (
' "\\n"\n'
' "%s [${name_struct_field} = %u] ",\n'
' line_prefix,\n'
' (guint)tmp.${underscore_struct_field});\n')
else:
template += (
' "\\n"\n'
' "%s [${name_struct_field} = %d] ",\n'
' line_prefix,\n'
' (gint)tmp.${underscore_struct_field});\n')
f.write(string.Template(template).substitute(translations))
f.write(
'\n'
' return g_string_free (printable, FALSE);\n'
'}\n')

View File

@ -1,15 +1,17 @@
EXTRA_DIST = \
TypeFactory.py \
Client.py \
MessageList.py \
Message.py \
Container.py \
ContainerInput.py \
ContainerOutput.py \
Field.py \
FieldArray.py \
FieldStruct.py \
FieldStructResult.py \
FieldBasic.py \
FieldResult.py \
Variable.py \
VariableFactory.py \
VariableArray.py \
VariableStruct.py \
VariableInteger.py \
VariableString.py \
utils.py \
qmi-codegen

View File

@ -21,10 +21,16 @@
import string
import utils
from ContainerOutput import ContainerOutput
from ContainerInput import ContainerInput
from Container import Container
"""
The Message class takes care of request/response message handling
"""
class Message:
"""
Constructor
"""
def __init__(self, dictionary, common_objects_dictionary):
# The message prefix
self.prefix = 'Qmi Message'
@ -48,19 +54,24 @@ class Message:
# Every defined message will have its own output container, which
# will generate a new Output type and public getters for each output
# field
self.output = ContainerOutput(self.fullname,
dictionary['output'],
common_objects_dictionary)
self.output = Container(self.fullname,
'Output',
dictionary['output'],
common_objects_dictionary)
# Build input container.
# Every defined message will have its own input container, which
# will generate a new Input type and public getters for each input
# field
self.input = ContainerInput(self.fullname,
dictionary['input'] if 'input' in dictionary else None,
common_objects_dictionary)
self.input = Container(self.fullname,
'Input',
dictionary['input'] if 'input' in dictionary else None,
common_objects_dictionary)
"""
Emit method responsible for creating a new request of the given type
"""
def __emit_request_creator(self, hfile, cfile):
translations = { 'name' : self.name,
'service' : self.service,
@ -161,6 +172,9 @@ class Message:
'}\n')
"""
Emit method responsible for parsing a response of the given type
"""
def __emit_response_parser(self, hfile, cfile):
translations = { 'name' : self.name,
'container' : utils.build_camelcase_name (self.output.fullname),
@ -219,6 +233,10 @@ class Message:
'}\n')
"""
Emit method responsible for getting a printable representation of the whole
request/response
"""
def __emit_get_printable(self, hfile, cfile):
if self.input.fields is not None:
@ -293,8 +311,6 @@ class Message:
' }\n'
' }\n'
'\n'
'\n'
'\n'
' if (!tlv_type_str) {\n'
' gchar *value_str = NULL;\n'
'\n'
@ -350,6 +366,9 @@ class Message:
cfile.write(string.Template(template).substitute(translations))
"""
Emit request/response handling implementation
"""
def emit(self, hfile, cfile):
utils.add_separator(hfile, 'REQUEST/RESPONSE', self.fullname);
utils.add_separator(cfile, 'REQUEST/RESPONSE', self.fullname);
@ -364,4 +383,6 @@ class Message:
self.output.emit(hfile, cfile)
self.__emit_response_parser(hfile, cfile)
hfile.write('\n/* --- Printable -- */\n');
cfile.write('\n/* --- Printable -- */\n');
self.__emit_get_printable(hfile, cfile)

View File

@ -23,7 +23,15 @@ import string
from Message import Message
import utils
"""
The MessageList class handles the generation of all messages for a given
specific service
"""
class MessageList:
"""
Constructor
"""
def __init__(self, objects_dictionary, common_objects_dictionary):
self.list = []
self.message_id_enum_name = None
@ -49,6 +57,9 @@ class MessageList:
raise ValueError('Missing Service field')
"""
Emit the enumeration of the messages found in the specific service
"""
def emit_message_ids_enum(self, f):
translations = { 'enum_type' : utils.build_camelcase_name (self.message_id_enum_name) }
template = (
@ -67,6 +78,10 @@ class MessageList:
f.write(string.Template(template).substitute(translations))
"""
Emit the method responsible for getting a printable representation of all
messages of a given service.
"""
def __emit_get_printable(self, hfile, cfile):
translations = { 'service' : string.lower(self.service) }
@ -103,6 +118,9 @@ class MessageList:
cfile.write(string.Template(template).substitute(translations))
"""
Emit the message list handling implementation
"""
def emit(self, hfile, cfile):
# First, emit the message IDs enum
self.emit_message_ids_enum(cfile)
@ -112,6 +130,6 @@ class MessageList:
message.emit(hfile, cfile)
# First, emit common class code
utils.add_separator(hfile, 'PRINTABLE', self.service);
utils.add_separator(cfile, 'PRINTABLE', self.service);
utils.add_separator(hfile, 'Service-specific printable', self.service);
utils.add_separator(cfile, 'Service-specific printable', self.service);
self.__emit_get_printable(hfile, cfile)

View File

@ -1,69 +0,0 @@
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2012 Lanedo GmbH
#
import string
import utils
class Struct:
def __init__(self, name, members):
# The struct type name, e.g. QmiTheStruct
self.name = name
# The struct members, a dictionary of 'format'+'name' pairs
self.members = members
# Emits the packed definition of the struct, meant to be private
def emit_packed(self, f):
translations = { 'name' : self.name }
template = (
'\n'
'typedef struct _${name}Packed {\n')
f.write(string.Template(template).substitute(translations))
for var in self.members:
translations['variable_type'] = var['format']
translations['variable_name'] = utils.build_underscore_name(var['name'])
template = (
' ${variable_type} ${variable_name};\n')
f.write(string.Template(template).substitute(translations))
template = ('} __attribute__((__packed__)) ${name}Packed;\n\n')
f.write(string.Template(template).substitute(translations))
# Emits the public non-packed definition of the struct
def emit(self, f):
translations = { 'name' : self.name }
template = (
'\n'
'typedef struct _${name} {\n')
f.write(string.Template(template).substitute(translations))
for var in self.members:
translations['variable_type'] = var['public-format'] if 'public-format' in var else var['format']
translations['variable_name'] = utils.build_underscore_name(var['name'])
template = (
' ${variable_type} ${variable_name};\n')
f.write(string.Template(template).substitute(translations))
template = ('} ${name};\n\n')
f.write(string.Template(template).substitute(translations))

View File

@ -0,0 +1,73 @@
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil -*-
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2012 Lanedo GmbH
#
"""
List to keep track of types already emitted to the source/header files.
"""
emitted_types = []
"""
Checks whether a given type has already been emitted.
"""
def is_type_emitted(type_name):
for i in emitted_types:
if i == type_name:
return True
else:
return False
"""
Sets the given type as already emitted.
"""
def set_type_emitted(type_name):
if is_type_emitted(type_name):
return False
else:
emitted_types.append(type_name)
return True
"""
List to keep track of type-specific get_printable() methods already emitted to
the source/header files.
"""
emitted_get_printable = []
"""
Checks whether a given type-specific get_printable() has already been emitted.
"""
def is_get_printable_emitted(type_name):
for i in emitted_get_printable:
if i == type_name:
return True
else:
return False
"""
Sets the given type-specific get_printable() as already emitted.
"""
def set_get_printable_emitted(type_name):
if is_get_printable_emitted(type_name):
return False
else:
emitted_get_printable.append(type_name)
return True

View File

@ -0,0 +1,93 @@
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2012 Lanedo GmbH
#
import string
import utils
"""
Base class for every variable type defined in the database
"""
class Variable:
"""
Constructor with common variable handling
"""
def __init__(self, dictionary):
"""
Variables can define specific public and private formats to be used.
The public format will be that used in the generated interface file,
while the private one will only be used internally.
"""
self.format = dictionary['format']
self.public_format = None
self.private_format = None
"""
Variables that get allocated in heap need to get properly disposed.
"""
self.needs_dispose = False
"""
Variables may suggest to be passed flagged as 'const' in the get/set
methods generated.
"""
self.pass_constant = False
"""
Emits the code to declare specific new types required by the variable.
"""
def emit_types(self, f):
pass
"""
Emits the code involved in reading the variable from the raw byte stream
into the specific private format.
"""
def emit_buffer_read(self, f, line_prefix, variable_name, buffer_name, buffer_len):
pass
"""
Emits the code involved in writing the variable to the raw byte stream
from the specific private format.
"""
def emit_buffer_write(self, f, line_prefix, variable_name, buffer_name, buffer_len):
pass
"""
Emits the code to get the contents of the given variable as a printable string.
"""
def emit_get_printable(self, f, line_prefix, printable, buffer_name, buffer_len):
pass
"""
Emits the code to copy a variable into another one of the same type.
"""
def emit_copy(self, f, line_prefix, variable_name_from, variable_name_to):
pass
"""
Emits the code to dispose the variable.
"""
def emit_dispose(self, f, line_prefix, variable_name):
pass

View File

@ -0,0 +1,185 @@
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2012 Lanedo GmbH
#
import string
import utils
from Variable import Variable
import VariableFactory
"""
Variable type for Arrays ('array' format)
"""
class VariableArray(Variable):
"""
Constructor
"""
def __init__(self, dictionary, array_element_type):
# Call the parent constructor
Variable.__init__(self, dictionary)
self.private_format = 'GArray *'
self.public_format = self.private_format
# The array and its contents need to get disposed
self.needs_dispose = True
# Load variable type of this array
if 'name' in dictionary['array-element']:
self.array_element = VariableFactory.create_variable(dictionary['array-element'], array_element_type + ' ' + dictionary['array-element']['name'])
else:
self.array_element = VariableFactory.create_variable(dictionary['array-element'], '')
"""
Emit the type for the array element
"""
def emit_types(self, f):
self.array_element.emit_types(f)
"""
Reading an array from the raw byte buffer is just about providing a loop to
read every array element one by one.
"""
def emit_buffer_read(self, f, line_prefix, variable_name, buffer_name, buffer_len):
translations = { 'lp' : line_prefix,
'private_format' : self.private_format,
'public_array_element_format' : self.array_element.public_format,
'variable_name' : variable_name,
'buffer_name' : buffer_name,
'buffer_len' : buffer_len }
template = (
'${lp}{\n'
'${lp} guint i;\n'
'${lp} guint8 n_items;\n'
'\n'
'${lp} /* Read number of items in the array */\n'
'${lp} n_items = ${buffer_name}[0];\n'
'${lp} ${buffer_name}++;\n'
'${lp} ${buffer_len}--;\n'
'\n'
'${lp} ${variable_name} = g_array_sized_new (\n'
'${lp} FALSE,\n'
'${lp} FALSE,\n'
'${lp} sizeof (${public_array_element_format}),\n'
'${lp} n_items);\n'
'\n'
'${lp} for (i = 0; i < n_items; i++) {\n'
'${lp} ${public_array_element_format} aux;\n'
'\n')
f.write(string.Template(template).substitute(translations))
self.array_element.emit_buffer_read(f, line_prefix + ' ', 'aux', buffer_name, buffer_len)
template = (
'${lp} g_array_insert_val (${variable_name}, i, aux);\n'
'${lp} }\n'
'${lp}}\n')
f.write(string.Template(template).substitute(translations))
"""
Writing an array to the raw byte buffer is just about providing a loop to
write every array element one by one.
"""
def emit_buffer_write(self, f, line_prefix, variable_name, buffer_name, buffer_len):
raise RuntimeError('Not implemented yet')
"""
The array will be printed as a list of fields enclosed between curly
brackets
"""
def emit_get_printable(self, f, line_prefix, printable, buffer_name, buffer_len):
translations = { 'lp' : line_prefix,
'printable' : printable,
'buffer_name' : buffer_name,
'buffer_len' : buffer_len }
template = (
'${lp}{\n'
'${lp} guint i;\n'
'${lp} guint8 n_items;\n'
'\n'
'${lp} /* Read number of items in the array */\n'
'${lp} n_items = ${buffer_name}[0];\n'
'${lp} ${buffer_name}++;\n'
'${lp} ${buffer_len}--;\n'
'\n'
'${lp} g_string_append (${printable}, "{");\n'
'\n'
'${lp} for (i = 0; i < n_items; i++) {\n'
'${lp} g_string_append_printf (${printable}, " [%u] = \'", i);\n')
f.write(string.Template(template).substitute(translations))
self.array_element.emit_get_printable(f, line_prefix + ' ', printable, buffer_name, buffer_len);
template = (
'${lp} g_string_append (${printable}, " \'");\n'
'${lp} }\n'
'\n'
'${lp} g_string_append (${printable}, "}");\n'
'${lp}}')
f.write(string.Template(template).substitute(translations))
"""
GArrays are ref-counted, so we can just provide a new ref to the array.
"""
def emit_copy(self, f, line_prefix, variable_name_from, variable_name_to):
translations = { 'lp' : line_prefix,
'from' : variable_name_from,
'to' : variable_name_to }
template = (
'${lp}${to} = g_array_ref (${from});\n')
f.write(string.Template(template).substitute(translations))
"""
FIXME: we should only dispose the members of the array if the refcount of
the array reached zero. Use g_array_set_clear_func() for that.
"""
def emit_dispose(self, f, line_prefix, variable_name):
translations = { 'lp' : line_prefix,
'variable_name' : variable_name }
if self.array_element.needs_dispose == True:
template = (
'${lp}{\n'
'${lp} guint i;\n'
'\n'
'${lp} for (i = 0; i < ${variable_name}->len; i++) {\n')
f.write(string.Template(template).substitute(translations))
self.array_element.emit_dispose(f, line_prefix, 'g_array_index (' + variable_name + ',' + self.array_element.public_format + ', i)')
template = (
'${lp} }\n'
'${lp}}')
f.write(string.Template(template).substitute(translations))
template = (
'${lp}g_array_unref (${variable_name});\n')
f.write(string.Template(template).substitute(translations))

View File

@ -18,21 +18,25 @@
# Copyright (C) 2012 Lanedo GmbH
#
import string
import utils
from VariableInteger import VariableInteger
from VariableString import VariableString
from VariableStruct import VariableStruct
from VariableArray import VariableArray
from Field import Field
from Container import Container
class ContainerInput(Container):
"""
The ContainerInput class takes care of handling collections of Input
fields
"""
def __init__(self, prefix, dictionary, common_objects_dictionary):
self.name = 'Input'
self.readonly = False
# Call the parent constructor
Container.__init__(self, prefix, dictionary, common_objects_dictionary)
"""
Helps in the creation of Variable objects based on the specific 'format' found
in the given dictionary
"""
def create_variable(dictionary, new_type_name):
if utils.format_is_integer(dictionary['format']):
return VariableInteger(dictionary)
elif dictionary['format'] == 'string':
return VariableString(dictionary)
elif dictionary['format'] == 'struct':
return VariableStruct(dictionary, new_type_name)
elif dictionary['format'] == 'array':
return VariableArray(dictionary, new_type_name)
else:
raise RuntimeError('Unexpected field format \'%s\'' % dictionary['format'])

View File

@ -0,0 +1,153 @@
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2012 Lanedo GmbH
#
import string
import utils
from Variable import Variable
"""
Variable type for signed/unsigned Integers
('guint8', 'gint8', 'guint16', 'gint16', 'guint32', 'gint32' formats)
"""
class VariableInteger(Variable):
"""
Constructor
"""
def __init__(self, dictionary):
# Call the parent constructor
Variable.__init__(self, dictionary)
self.private_format = self.format
self.public_format = dictionary['public-format'] if 'public-format' in dictionary else self.private_format
"""
Read a single integer from the raw byte buffer
"""
def emit_buffer_read(self, f, line_prefix, variable_name, buffer_name, buffer_len):
translations = { 'lp' : line_prefix,
'public_format' : self.public_format,
'private_format' : self.private_format,
'variable_name' : variable_name,
'buffer_name' : buffer_name,
'buffer_len' : buffer_len }
if self.private_format == self.public_format:
template = (
'${lp}/* Read the ${private_format} variable from the buffer */\n'
'${lp}qmi_utils_read_${private_format}_from_buffer (\n'
'${lp} &${buffer_name},\n'
'${lp} &${buffer_len},\n'
'${lp} &(${variable_name}));\n')
else:
template = (
'${lp}{\n'
'${lp} ${private_format} tmp;\n'
'\n'
'${lp} /* Read the ${private_format} variable from the buffer */\n'
'${lp} qmi_utils_read_${private_format}_from_buffer (\n'
'${lp} &${buffer_name},\n'
'${lp} &${buffer_len},\n'
'${lp} &tmp);\n'
'${lp} ${variable_name} = (${public_format})tmp;\n'
'${lp}}\n')
f.write(string.Template(template).substitute(translations))
"""
Write a single integer to the raw byte buffer
"""
def emit_buffer_write(self, f, line_prefix, variable_name, buffer_name, buffer_len):
translations = { 'lp' : line_prefix,
'private_format' : self.private_format,
'variable_name' : variable_name,
'buffer_name' : buffer_name,
'buffer_len' : buffer_len }
if self.private_format == self.public_format:
template = (
'${lp}/* Write the ${private_format} variable to the buffer */\n'
'${lp}qmi_utils_write_${private_format}_to_buffer (\n'
'${lp} &${buffer_name},\n'
'${lp} &${buffer_len},\n'
'${lp} &(${variable_name}));\n')
else:
template = (
'${lp}{\n'
'${lp} ${private_format} tmp;\n'
'\n'
'${lp} tmp = (${private_format})${variable_name};\n'
'${lp} /* Write the ${private_format} variable to the buffer */\n'
'${lp} qmi_utils_write_${private_format}_to_buffer (\n'
'${lp} &${buffer_name},\n'
'${lp} &${buffer_len},\n'
'${lp} &tmp);\n'
'${lp}}\n')
f.write(string.Template(template).substitute(translations))
"""
Get the integer as a printable string. Given that we support max 32-bit
integers, it is safe to cast all them to standard integers when printing.
"""
def emit_get_printable(self, f, line_prefix, printable, buffer_name, buffer_len):
if utils.format_is_unsigned_integer(self.private_format):
common_format = '%u'
common_cast = 'guint'
else:
common_format = '%d'
common_cast = 'gint'
translations = { 'lp' : line_prefix,
'private_format' : self.private_format,
'printable' : printable,
'buffer_name' : buffer_name,
'buffer_len' : buffer_len,
'common_format' : common_format,
'common_cast' : common_cast }
template = (
'\n'
'${lp}{\n'
'${lp} ${private_format} tmp;\n'
'\n'
'${lp} /* Read the ${private_format} variable from the buffer */\n'
'${lp} qmi_utils_read_${private_format}_from_buffer (\n'
'${lp} &${buffer_name},\n'
'${lp} &${buffer_len},\n'
'${lp} &tmp);\n'
'\n'
'${lp} g_string_append_printf (${printable}, "${common_format}", (${common_cast})tmp);\n'
'${lp}}\n')
f.write(string.Template(template).substitute(translations))
"""
Copy an integer to another one
"""
def emit_copy(self, f, line_prefix, variable_name_from, variable_name_to):
translations = { 'lp' : line_prefix,
'from' : variable_name_from,
'to' : variable_name_to }
template = (
'${lp}${to} = ${from};\n')
f.write(string.Template(template).substitute(translations))

View File

@ -0,0 +1,142 @@
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2012 Lanedo GmbH
#
import string
import utils
from Variable import Variable
"""
Variable type for Strings ('string' format)
"""
class VariableString(Variable):
"""
Constructor
"""
def __init__(self, dictionary):
# Call the parent constructor
Variable.__init__(self, dictionary)
self.private_format = 'gchar *'
self.public_format = self.private_format
# Strings will be heap-allocated
self.needs_dispose = True
# We want to get the strings be passed as 'const'
self.pass_constant = True
# Strings which are given as the full value of a TLV will NOT have a
# length prefix
self.length_prefix = False if 'type' in dictionary and dictionary['type'] == 'TLV' else True
"""
Read a string from the raw byte buffer.
"""
def emit_buffer_read(self, f, line_prefix, variable_name, buffer_name, buffer_len):
translations = { 'lp' : line_prefix,
'variable_name' : variable_name,
'buffer_name' : buffer_name,
'buffer_len' : buffer_len,
'length_prefix' : 'TRUE' if self.length_prefix else 'FALSE' }
template = (
'${lp}/* Read the string variable from the buffer */\n'
'${lp}qmi_utils_read_string_from_buffer (\n'
'${lp} &${buffer_name},\n'
'${lp} &${buffer_len},\n'
'${lp} ${length_prefix},\n'
'${lp} &(${variable_name}));\n')
f.write(string.Template(template).substitute(translations))
"""
Write a string to the raw byte buffer.
"""
def emit_buffer_write(self, f, line_prefix, variable_name, buffer_name, buffer_len):
translations = { 'lp' : line_prefix,
'variable_name' : variable_name,
'buffer_name' : buffer_name,
'buffer_len' : buffer_len,
'length_prefix' : 'TRUE' if self.length_prefix else 'FALSE' }
template = (
'${lp}/* Write the string variable to the buffer */\n'
'${lp}qmi_utils_write_string_to_buffer (\n'
'${lp} &${buffer_name},\n'
'${lp} &${buffer_len},\n'
'${lp} ${length_prefix},\n'
'${lp} &(${variable_name}));\n')
f.write(string.Template(template).substitute(translations))
"""
Get the string as printable
"""
def emit_get_printable(self, f, line_prefix, printable, buffer_name, buffer_len):
translations = { 'lp' : line_prefix,
'printable' : printable,
'buffer_name' : buffer_name,
'buffer_len' : buffer_len,
'length_prefix' : 'TRUE' if self.length_prefix else 'FALSE' }
template = (
'\n'
'${lp}{\n'
'${lp} gchar *tmp;\n'
'\n'
'${lp} /* Read the string variable from the buffer */\n'
'${lp} qmi_utils_read_string_from_buffer (\n'
'${lp} &${buffer_name},\n'
'${lp} &${buffer_len},\n'
'${lp} ${length_prefix},\n'
'${lp} &tmp);\n'
'\n'
'${lp} g_string_append_printf (${printable}, "%s", tmp);\n'
'${lp} g_free (tmp);\n'
'${lp}}\n')
f.write(string.Template(template).substitute(translations))
"""
Copy the string
"""
def emit_copy(self, f, line_prefix, variable_name_from, variable_name_to):
translations = { 'lp' : line_prefix,
'from' : variable_name_from,
'to' : variable_name_to }
template = (
'${lp}${to} = g_strdup (${from});\n')
f.write(string.Template(template).substitute(translations))
"""
Dispose the string
"""
def emit_dispose(self, f, line_prefix, variable_name):
translations = { 'lp' : line_prefix,
'variable_name' : variable_name }
template = (
'${lp}g_free (${variable_name});\n')
f.write(string.Template(template).substitute(translations))

View File

@ -0,0 +1,146 @@
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2012 Lanedo GmbH
#
import string
import utils
from Variable import Variable
import VariableFactory
"""
Variable type for Structs ('struct' format)
"""
class VariableStruct(Variable):
"""
Constructor
"""
def __init__(self, dictionary, struct_type_name):
# Call the parent constructor
Variable.__init__(self, dictionary)
# The public format of the struct is built directly from the suggested
# struct type name
self.public_format = utils.build_camelcase_name(struct_type_name)
self.private_format = self.public_format
# Load members of this struct
self.members = []
for member_dictionary in dictionary['contents']:
member = {}
member['name'] = utils.build_underscore_name(member_dictionary['name'])
member['object'] = VariableFactory.create_variable(member_dictionary, struct_type_name + ' ' + member['name'])
self.members.append(member)
# We'll need to dispose if at least one of the members needs it
for member in self.members:
if member['object'].needs_dispose == True:
self.needs_dispose = True
"""
Emit all types for the members of the struct plus the new struct type itself
"""
def emit_types(self, f):
# Emit types for each member
for member in self.members:
member['object'].emit_types(f)
translations = { 'format' : self.public_format }
template = (
'\n'
'typedef struct _${format} {\n')
f.write(string.Template(template).substitute(translations))
for member in self.members:
translations['variable_format'] = member['object'].public_format
translations['variable_name'] = member['name']
template = (
' ${variable_format} ${variable_name};\n')
f.write(string.Template(template).substitute(translations))
template = ('} ${format};\n')
f.write(string.Template(template).substitute(translations))
"""
Reading the contents of a struct is just about reading each of the struct
fields one by one.
"""
def emit_buffer_read(self, f, line_prefix, variable_name, buffer_name, buffer_len):
for member in self.members:
member['object'].emit_buffer_read(f, line_prefix, variable_name + '.' + member['name'], buffer_name, buffer_len)
"""
Writing the contents of a struct is just about writing each of the struct
fields one by one.
"""
def emit_buffer_write(self, f, line_prefix, variable_name, buffer_name, buffer_len):
for member in self.members:
member['object'].emit_buffer_write(f, line_prefix, variable_name + '.' + member['name'], buffer_name, buffer_len)
"""
The struct will be printed as a list of fields enclosed between square
brackets
"""
def emit_get_printable(self, f, line_prefix, printable, buffer_name, buffer_len):
translations = { 'lp' : line_prefix,
'printable' : printable }
template = (
'${lp}g_string_append (${printable}, "[");\n')
f.write(string.Template(template).substitute(translations))
for member in self.members:
translations['variable_name'] = member['name']
template = (
'${lp}g_string_append (${printable}, " ${variable_name} = \'");\n')
f.write(string.Template(template).substitute(translations))
member['object'].emit_get_printable(f, line_prefix, printable, buffer_name, buffer_len)
template = (
'${lp}g_string_append (${printable}, "\'");\n')
f.write(string.Template(template).substitute(translations))
template = (
'${lp}g_string_append (${printable}, " ]");\n')
f.write(string.Template(template).substitute(translations))
"""
Copying a struct is just about copying each of the struct fields one by one.
Note that we shouldn't just "a = b" with the structs, as the members may be
heap-allocated strings.
"""
def emit_copy(self, f, line_prefix, variable_name_from, variable_name_to):
for member in self.members:
member['object'].emit_copy(f, line_prefix, variable_name_from + '.' + member['name'], variable_name_to + '.' + member['name'])
"""
Disposing a struct is just about disposing each of the struct fields one by
one.
"""
def emit_dispose(self, f, line_prefix, variable_name):
for member in self.members:
member['object'].emit_dispose(f, line_prefix, variable_name + '.' + member['name'])

View File

@ -20,35 +20,47 @@
import string
"""
Add the common copyright header to the given file
"""
def add_copyright(f):
f.write("\n"
"/* GENERATED CODE... DO NOT EDIT */\n"
"\n"
"/*\n"
" * This library is free software; you can redistribute it and/or\n"
" * modify it under the terms of the GNU Lesser General Public\n"
" * License as published by the Free Software Foundation; either\n"
" * version 2 of the License, or (at your option) any later version.\n"
" *\n"
" * This library is distributed in the hope that it will be useful,\n"
" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
" * Lesser General Public License for more details.\n"
" *\n"
" * You should have received a copy of the GNU Lesser General Public\n"
" * License along with this library; if not, write to the\n"
" * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,\n"
" * Boston, MA 02110-1301 USA.\n"
" *\n"
" * Copyright (C) 2012 Lanedo GmbH\n"
" */\n"
"\n");
f.write(
"\n"
"/* GENERATED CODE... DO NOT EDIT */\n"
"\n"
"/*\n"
" * This library is free software; you can redistribute it and/or\n"
" * modify it under the terms of the GNU Lesser General Public\n"
" * License as published by the Free Software Foundation; either\n"
" * version 2 of the License, or (at your option) any later version.\n"
" *\n"
" * This library is distributed in the hope that it will be useful,\n"
" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
" * Lesser General Public License for more details.\n"
" *\n"
" * You should have received a copy of the GNU Lesser General Public\n"
" * License along with this library; if not, write to the\n"
" * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,\n"
" * Boston, MA 02110-1301 USA.\n"
" *\n"
" * Copyright (C) 2012 Lanedo GmbH\n"
" */\n"
"\n");
"""
Build a header guard string based on the given filename
"""
def build_header_guard(output_name):
return "__LIBQMI_GLIB_" + string.upper(string.replace (output_name, '-', '_')) + "__"
"""
Write the common header start chunk
"""
def add_header_start(f, output_name):
template = string.Template (
template = string.Template(
"\n"
"#ifndef ${guard}\n"
"#define ${guard}\n"
@ -65,6 +77,10 @@ def add_header_start(f, output_name):
"\n")
f.write(template.substitute(guard = build_header_guard(output_name)))
"""
Write the common header stop chunk
"""
def add_header_stop(f, output_name):
template = string.Template (
"\n"
@ -73,19 +89,10 @@ def add_header_stop(f, output_name):
"#endif /* ${guard} */\n")
f.write(template.substitute(guard = build_header_guard(output_name)))
#def add_global_include(f, header):
# template = string.Template (
# "\n"
# "#include <${header}>\n")
# f.write(template.substitute(header = header))
#
#def add_local_include(f, header):
# template = string.Template (
# "\n"
# "#include \"${header}\"\n")
# f.write(template.substitute(header = header))
"""
Write the common source file start chunk
"""
def add_source_start(f, output_name):
template = string.Template (
"\n"
@ -102,6 +109,9 @@ def add_source_start(f, output_name):
f.write(template.substitute(name = output_name))
"""
Write a separator comment in the file
"""
def add_separator(f, separator_type, separator_name):
template = string.Template (
"\n"
@ -111,46 +121,27 @@ def add_separator(f, separator_type, separator_name):
f.write(template.substitute(type = separator_type,
name = separator_name))
"""
Build an underscore name from the given full name
e.g.: "This is a message" --> "this_is_a_message"
"""
def build_underscore_name(name):
return string.lower(string.replace (name, ' ', '_'))
"""
Build a camelcase name from the given full name
e.g.: "This is a message" --> "ThisIsAMessage"
"""
def build_camelcase_name(name):
return string.replace(string.capwords(name), ' ', '')
#def emit_struct_type(f, struct_type, dictionary):
# translations = { 'struct_type' : struct_type }
# template = (
# '\n'
# 'typedef struct _${struct_type} {\n')
# f.write(string.Template(template).substitute(translations))
# for var in dictionary['contents']:
# translations['variable_type'] = var['type']
# translations['variable_name'] = build_underscore_name(var['name'])
# template = (
# ' ${variable_type} ${variable_name};\n')
# f.write(string.Template(template).substitute(translations))
# template = ('} __attribute__((__packed__)) ${struct_type};\n\n')
# f.write(string.Template(template).substitute(translations))
def he_from_le(input_variable, output_variable, variable_type):
if variable_type == 'guint16':
return '%s = GUINT16_FROM_LE (%s)' % (output_variable, input_variable)
elif variable_type == 'guint32':
return '%s = GUINT32_FROM_LE (%s)' % (output_variable, input_variable)
if variable_type == 'gint16':
return '%s = GINT16_FROM_LE (%s)' % (output_variable, input_variable)
elif variable_type == 'gint32':
return '%s = GINT32_FROM_LE (%s)' % (output_variable, input_variable)
else:
return '%s = %s' % (output_variable, input_variable)
def le_from_he(input_variable, output_variable, variable_type):
return he_from_le(input_variable, output_variable, variable_type)
"""
Read the contents of the JSON file, skipping lines prefixed with '//', which are
considered comments.
"""
def read_json_file(path):
f = open(path)
out = ''
@ -162,3 +153,39 @@ def read_json_file(path):
else:
out += line
return out
"""
Returns True if the given format corresponds to a basic unsigned integer type
"""
def format_is_unsigned_integer(fmt):
if fmt == 'guint8' or \
fmt == 'guint16' or \
fmt == 'guint32':
return True
else:
return False
"""
Returns True if the given format corresponds to a basic signed integer type
"""
def format_is_signed_integer(fmt):
if fmt == 'gint8' or \
fmt == 'gint16' or \
fmt == 'gint32':
return True
else:
return False
"""
Returns True if the given format corresponds to a basic signed or unsigned
integer type
"""
def format_is_integer(fmt):
if format_is_unsigned_integer(fmt) or \
format_is_signed_integer(fmt):
return True
else:
return False

View File

@ -45,30 +45,30 @@
#define PACKED __attribute__((packed))
struct qmux {
uint16_t length;
uint8_t flags;
uint8_t service;
uint8_t client;
guint16 length;
guint8 flags;
guint8 service;
guint8 client;
} PACKED;
struct control_header {
uint8_t flags;
uint8_t transaction;
uint16_t message;
uint16_t tlv_length;
guint8 flags;
guint8 transaction;
guint16 message;
guint16 tlv_length;
} PACKED;
struct service_header {
uint8_t flags;
uint16_t transaction;
uint16_t message;
uint16_t tlv_length;
guint8 flags;
guint16 transaction;
guint16 message;
guint16 tlv_length;
} PACKED;
struct tlv {
uint8_t type;
uint16_t length;
char value[];
guint8 type;
guint16 length;
guint8 value[];
} PACKED;
struct control_message {
@ -82,7 +82,7 @@ struct service_message {
} PACKED;
struct full_message {
uint8_t marker;
guint8 marker;
struct qmux qmux;
union {
struct control_message control;
@ -105,7 +105,7 @@ qmi_message_get_qmux_length (QmiMessage *self)
static inline void
set_qmux_length (QmiMessage *self,
uint16_t length)
guint16 length)
{
self->buf->qmux.length = GUINT16_TO_LE (length);
}
@ -223,7 +223,7 @@ qmi_message_get_tlv_length (QmiMessage *self)
static void
set_qmi_message_get_tlv_length (QmiMessage *self,
guint16 length)
guint16 length)
{
if (qmi_message_is_control (self))
self->buf->qmi.control.header.tlv_length = GUINT16_TO_LE (length);
@ -240,16 +240,16 @@ qmi_tlv (QmiMessage *self)
return self->buf->qmi.service.tlv;
}
static char *
static guint8 *
qmi_end (QmiMessage *self)
{
return (char *) self->buf + self->len;
return (guint8 *) self->buf + self->len;
}
static struct tlv *
tlv_next (struct tlv *tlv)
{
return (struct tlv *)((char *)tlv + sizeof(struct tlv) + le16toh (tlv->length));
return (struct tlv *)((guint8 *)tlv + sizeof(struct tlv) + le16toh (tlv->length));
}
static struct tlv *
@ -290,7 +290,7 @@ qmi_message_check (QmiMessage *self,
GError **error)
{
gsize header_length;
gchar *end;
guint8 *end;
struct tlv *tlv;
g_assert (self != NULL);
@ -407,7 +407,7 @@ qmi_message_new (QmiService service,
if (service == QMI_SERVICE_CTL) {
self->buf->qmi.control.header.flags = 0;
self->buf->qmi.control.header.transaction = (uint8_t)transaction_id;
self->buf->qmi.control.header.transaction = (guint8)transaction_id;
self->buf->qmi.control.header.message = htole16 (message_id);
} else {
self->buf->qmi.service.header.flags = 0;
@ -457,13 +457,12 @@ qmi_message_get_raw (QmiMessage *self,
return self->buf;
}
static gboolean
qmimsg_tlv_get_internal (QmiMessage *self,
guint8 type,
guint16 *length,
gpointer value,
gboolean length_exact,
GError **error)
gboolean
qmi_message_tlv_get (QmiMessage *self,
guint8 type,
guint16 *length,
guint8 **value,
GError **error)
{
struct tlv *tlv;
@ -474,27 +473,9 @@ qmimsg_tlv_get_internal (QmiMessage *self,
for (tlv = qmi_tlv_first (self); tlv; tlv = qmi_tlv_next (self, tlv)) {
if (tlv->type == type) {
if (length_exact && (le16toh (tlv->length) != *length)) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_TLV_NOT_FOUND,
"TLV found but wrong length (%u != %u)",
tlv->length,
*length);
return FALSE;
} else if (value && le16toh (tlv->length) > *length) {
g_set_error (error,
QMI_CORE_ERROR,
QMI_CORE_ERROR_TLV_TOO_LONG,
"TLV found but too long (%u > %u)",
le16toh (tlv->length),
*length);
return FALSE;
}
*length = le16toh (tlv->length);
*length = GUINT16_FROM_LE (tlv->length);
if (value)
memcpy (value, tlv->value, le16toh (tlv->length));
*value = &(tlv->value[0]);
return TRUE;
}
}
@ -506,49 +487,6 @@ qmimsg_tlv_get_internal (QmiMessage *self,
return FALSE;
}
gboolean
qmi_message_tlv_get (QmiMessage *self,
guint8 type,
guint16 length,
gpointer value,
GError **error)
{
return qmimsg_tlv_get_internal (self, type, &length, value, TRUE, error);
}
gboolean
qmi_message_tlv_get_varlen (QmiMessage *self,
guint8 type,
guint16 *length,
gpointer value,
GError **error)
{
return qmimsg_tlv_get_internal (self, type, length, value, FALSE, error);
}
gchar *
qmi_message_tlv_get_string (QmiMessage *self,
guint8 type,
GError **error)
{
uint16_t length;
gchar *value;
/* Read length only first */
if (!qmi_message_tlv_get_varlen (self, type, &length, NULL, error))
return NULL;
/* Read exact length and value */
value = g_malloc (length + 1);
if (!qmi_message_tlv_get (self, type, length, value, error)) {
g_free (value);
return NULL;
}
value[length] = '\0';
return value;
}
void
qmi_message_tlv_foreach (QmiMessage *self,
QmiMessageForeachTlvFn callback,
@ -610,8 +548,8 @@ qmi_message_tlv_add (QmiMessage *self,
memcpy (tlv->value, value, length);
/* Update length fields. */
set_qmux_length (self, (uint16_t)(qmi_message_get_qmux_length (self) + tlv_len));
set_qmi_message_get_tlv_length (self, (uint16_t)(qmi_message_get_tlv_length(self) + tlv_len));
set_qmux_length (self, (guint16)(qmi_message_get_qmux_length (self) + tlv_len));
set_qmi_message_get_tlv_length (self, (guint16)(qmi_message_get_tlv_length(self) + tlv_len));
/* Make sure we didn't break anything. */
if (!qmi_message_check (self, error)) {

View File

@ -56,20 +56,11 @@ void qmi_message_tlv_foreach (QmiMessage *self,
QmiMessageForeachTlvFn callback,
gpointer user_data);
gboolean qmi_message_tlv_get (QmiMessage *self,
guint8 type,
guint16 length,
gpointer value,
GError **error);
gboolean qmi_message_tlv_get_varlen (QmiMessage *self,
guint8 type,
guint16 *length,
gpointer value,
GError **error);
gchar *qmi_message_tlv_get_string (QmiMessage *self,
guint8 type,
GError **error);
gboolean qmi_message_tlv_get (QmiMessage *self,
guint8 type,
guint16 *length,
guint8 **value,
GError **error);
gboolean qmi_message_tlv_add (QmiMessage *self,
guint8 type,

View File

@ -60,3 +60,253 @@ qmi_utils_str_hex (gconstpointer mem,
/* Set output string */
return new_str;
}
void
qmi_utils_read_guint8_from_buffer (guint8 **buffer,
guint16 *buffer_size,
guint8 *out)
{
g_assert (out != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
g_assert (*buffer_size >= 1);
*out = (*buffer)[0];
*buffer = &((*buffer)[1]);
*buffer_size = (*buffer_size) - 1;
}
void
qmi_utils_read_gint8_from_buffer (guint8 **buffer,
guint16 *buffer_size,
gint8 *out)
{
g_assert (out != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
g_assert (*buffer_size >= 1);
*out = *((gint8 *)(&((*buffer)[0])));
*buffer = &((*buffer)[1]);
*buffer_size = (*buffer_size) - 1;
}
void
qmi_utils_read_guint16_from_buffer (guint8 **buffer,
guint16 *buffer_size,
guint16 *out)
{
g_assert (out != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
g_assert (*buffer_size >= 2);
*out = GUINT16_FROM_LE (*((guint16 *)&((*buffer)[0])));
*buffer = &((*buffer)[2]);
*buffer_size = (*buffer_size) - 2;
}
void
qmi_utils_read_gint16_from_buffer (guint8 **buffer,
guint16 *buffer_size,
gint16 *out)
{
g_assert (out != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
g_assert (*buffer_size >= 2);
*out = GINT16_FROM_LE (*((guint16 *)&((*buffer)[0])));
*buffer = &((*buffer)[2]);
*buffer_size = (*buffer_size) - 2;
}
void
qmi_utils_read_guint32_from_buffer (guint8 **buffer,
guint16 *buffer_size,
guint32 *out)
{
g_assert (out != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
g_assert (*buffer_size >= 4);
*out = GUINT32_FROM_LE (*((guint32 *)&((*buffer)[0])));
*buffer = &((*buffer)[4]);
*buffer_size = (*buffer_size) - 4;
}
void
qmi_utils_read_gint32_from_buffer (guint8 **buffer,
guint16 *buffer_size,
gint32 *out)
{
g_assert (out != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
g_assert (*buffer_size >= 4);
*out = GUINT32_FROM_LE (*((guint32 *)&((*buffer)[0])));
*buffer = &((*buffer)[4]);
*buffer_size = (*buffer_size) - 4;
}
void
qmi_utils_write_guint8_to_buffer (guint8 **buffer,
guint16 *buffer_size,
guint8 *in)
{
g_assert (in != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
g_assert (*buffer_size >= 1);
(*buffer)[0] = *in;
*buffer = &((*buffer)[1]);
*buffer_size = (*buffer_size) - 1;
}
void
qmi_utils_write_gint8_to_buffer (guint8 **buffer,
guint16 *buffer_size,
gint8 *in)
{
g_assert (in != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
g_assert (*buffer_size >= 1);
*((gint8 *)(&((*buffer)[0]))) = *in;
*buffer = &((*buffer)[1]);
*buffer_size = (*buffer_size) - 1;
}
void
qmi_utils_write_guint16_to_buffer (guint8 **buffer,
guint16 *buffer_size,
guint16 *in)
{
g_assert (in != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
g_assert (*buffer_size >= 2);
*((guint16 *)(&((*buffer)[0]))) = GUINT16_TO_LE (*in);
*buffer = &((*buffer)[2]);
*buffer_size = (*buffer_size) - 2;
}
void
qmi_utils_write_gint16_to_buffer (guint8 **buffer,
guint16 *buffer_size,
gint16 *in)
{
g_assert (in != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
g_assert (*buffer_size >= 2);
*((gint16 *)(&((*buffer)[0]))) = GINT16_TO_LE (*in);
*buffer = &((*buffer)[2]);
*buffer_size = (*buffer_size) - 2;
}
void
qmi_utils_write_guint32_to_buffer (guint8 **buffer,
guint16 *buffer_size,
guint32 *in)
{
g_assert (in != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
g_assert (*buffer_size >= 4);
*((guint32 *)(&((*buffer)[0]))) = GUINT32_TO_LE (*in);
*buffer = &((*buffer)[4]);
*buffer_size = (*buffer_size) - 4;
}
void
qmi_utils_write_gint32_to_buffer (guint8 **buffer,
guint16 *buffer_size,
gint32 *in)
{
g_assert (in != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
g_assert (*buffer_size >= 4);
*((gint32 *)(&((*buffer)[0]))) = GINT32_TO_LE (*in);
*buffer = &((*buffer)[4]);
*buffer_size = (*buffer_size) - 4;
}
void
qmi_utils_read_string_from_buffer (guint8 **buffer,
guint16 *buffer_size,
gboolean length_prefix,
gchar **out)
{
guint16 string_length;
g_assert (out != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
/* If no length prefix given, read the whole buffer into a string */
if (!length_prefix)
string_length = *buffer_size;
else {
/* We assume the length prefix is always a guint8 */
guint8 string_length_8;
qmi_utils_read_guint8_from_buffer (buffer, buffer_size, &string_length_8);
string_length = string_length_8;
}
*out = g_malloc (string_length + 1);
(*out)[string_length] = '\0';
memcpy (*out, *buffer, string_length);
*buffer = &((*buffer)[string_length]);
*buffer_size = (*buffer_size) - string_length;
}
void
qmi_utils_write_string_to_buffer (guint8 **buffer,
guint16 *buffer_size,
gboolean length_prefix,
gchar **in)
{
guint16 len;
g_assert (in != NULL);
g_assert (buffer != NULL);
g_assert (buffer_size != NULL);
len = (guint16) strlen (*in);
if (length_prefix) {
guint8 len_8;
g_warn_if_fail (len <= G_MAXUINT8);
len_8 = (guint8)len;
qmi_utils_write_guint8_to_buffer (buffer, buffer_size, &len_8);
}
memcpy (*buffer, *in, len);
*buffer = &((*buffer)[len]);
*buffer_size = (*buffer_size) - len;
}

View File

@ -34,6 +34,62 @@ gchar *qmi_utils_str_hex (gconstpointer mem,
gsize size,
gchar delimiter);
/* Reading/Writing integer variables */
void qmi_utils_read_guint8_from_buffer (guint8 **buffer,
guint16 *buffer_size,
guint8 *out);
void qmi_utils_read_gint8_from_buffer (guint8 **buffer,
guint16 *buffer_size,
gint8 *out);
void qmi_utils_read_guint16_from_buffer (guint8 **buffer,
guint16 *buffer_size,
guint16 *out);
void qmi_utils_read_gint16_from_buffer (guint8 **buffer,
guint16 *buffer_size,
gint16 *out);
void qmi_utils_read_guint32_from_buffer (guint8 **buffer,
guint16 *buffer_size,
guint32 *out);
void qmi_utils_read_gint32_from_buffer (guint8 **buffer,
guint16 *buffer_size,
gint32 *out);
void qmi_utils_write_guint8_to_buffer (guint8 **buffer,
guint16 *buffer_size,
guint8 *in);
void qmi_utils_write_gint8_to_buffer (guint8 **buffer,
guint16 *buffer_size,
gint8 *in);
void qmi_utils_write_guint16_to_buffer (guint8 **buffer,
guint16 *buffer_size,
guint16 *in);
void qmi_utils_write_gint16_to_buffer (guint8 **buffer,
guint16 *buffer_size,
gint16 *in);
void qmi_utils_write_guint32_to_buffer (guint8 **buffer,
guint16 *buffer_size,
guint32 *in);
void qmi_utils_write_gint32_to_buffer (guint8 **buffer,
guint16 *buffer_size,
gint32 *in);
/* Reading/Writing string variables */
void qmi_utils_read_string_from_buffer (guint8 **buffer,
guint16 *buffer_size,
gboolean length_prefix,
gchar **out);
void qmi_utils_write_string_to_buffer (guint8 **buffer,
guint16 *buffer_size,
gboolean length_prefix,
gchar **in);
G_END_DECLS
#endif /* _LIBQMI_GLIB_QMI_UTILS_H_ */