| #!/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, container_type): |
| |
| # Call the parent constructor |
| Variable.__init__(self, dictionary) |
| |
| self.private_format = 'GArray *' |
| self.public_format = self.private_format |
| self.fixed_size = 0 |
| self.name = dictionary['name'] |
| |
| # The array and its contents need to get disposed |
| self.needs_dispose = True |
| |
| # We need to know whether the variable comes in an Input container or in |
| # an Output container, as we should not dump the element clear() helper method |
| # if the variable is from an Input container. |
| self.container_type = container_type |
| |
| # 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'], self.container_type) |
| else: |
| self.array_element = VariableFactory.create_variable(dictionary['array-element'], '', self.container_type) |
| |
| # Load variable type for the array size prefix |
| if 'size-prefix-format' in dictionary: |
| # We do NOT allow 64-bit types as array sizes (GArray won't support them) |
| if dictionary['size-prefix-format'] not in [ 'guint8', 'guint16', 'guint32' ]: |
| raise ValueError('Invalid size prefix format (%s): not guint8 or guint16 or guint32' % dictionary['size-prefix-format']) |
| default_array_size = { 'format' : dictionary['size-prefix-format'] } |
| self.array_size_element = VariableFactory.create_variable(default_array_size, '', self.container_type) |
| elif 'fixed-size' in dictionary: |
| # fixed-size arrays have no size element, obviously |
| self.fixed_size = dictionary['fixed-size'] |
| if int(self.fixed_size) == 0 or int(self.fixed_size) > 512: |
| raise ValueError('Fixed array size %s out of bounds (not between 0 and 512)' % self.fixed_size) |
| else: |
| # Default to 'guint8' if no explicit array size given |
| default_array_size = { 'format' : 'guint8' } |
| self.array_size_element = VariableFactory.create_variable(default_array_size, '', self.container_type) |
| |
| # Load variable type for the sequence prefix |
| if 'sequence-prefix-format' in dictionary: |
| sequence = { 'format' : dictionary['sequence-prefix-format'] } |
| self.array_sequence_element = VariableFactory.create_variable(sequence, '', self.container_type) |
| else: |
| self.array_sequence_element = '' |
| |
| |
| """ |
| Emit the type for the array element |
| """ |
| def emit_types(self, f): |
| self.array_element.emit_types(f) |
| |
| |
| """ |
| Constructs the name of the array clear function |
| """ |
| def clear_func_name(self): |
| # element public format might be a base type like 'gchar *' rather |
| # than a structure name like QmiFooBar |
| elt_name = self.array_element.public_format.replace('*', 'pointer') |
| return utils.build_underscore_name(self.name) + \ |
| '_' + \ |
| utils.build_underscore_name_from_camelcase(utils.build_camelcase_name(elt_name)) |
| |
| |
| """ |
| Emits the code to clear the element of the array |
| """ |
| def emit_helper_methods(self, hfile, cfile): |
| self.array_element.emit_helper_methods(hfile, cfile) |
| |
| # No need for the clear func if no need to dispose the contents |
| if self.array_element.needs_dispose == False: |
| return |
| |
| # No need for the clear func if we were not the ones who created |
| # the array |
| if self.container_type == "Input": |
| return |
| |
| translations = { 'element_format' : self.array_element.public_format, |
| 'underscore' : self.clear_func_name(), |
| 'dispose_contents' : self.array_element.build_dispose(' ', '(*p)') } |
| |
| template = ( |
| '\n' |
| 'static void\n' |
| '${underscore}_clear (${element_format} *p)\n' |
| '{\n' |
| '$dispose_contents' |
| '}\n') |
| cfile.write(string.Template(template).substitute(translations)) |
| |
| |
| """ |
| 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): |
| common_var_prefix = utils.build_underscore_name(self.name) |
| translations = { 'lp' : line_prefix, |
| 'private_format' : self.private_format, |
| 'public_array_element_format' : self.array_element.public_format, |
| 'underscore' : self.clear_func_name(), |
| 'variable_name' : variable_name, |
| 'buffer_name' : buffer_name, |
| 'buffer_len' : buffer_len, |
| 'common_var_prefix' : common_var_prefix } |
| |
| template = ( |
| '${lp}{\n' |
| '${lp} guint ${common_var_prefix}_i;\n') |
| f.write(string.Template(template).substitute(translations)) |
| |
| if self.fixed_size: |
| translations['fixed_size'] = self.fixed_size |
| |
| template = ( |
| '${lp} guint16 ${common_var_prefix}_n_items = ${fixed_size};\n' |
| '\n') |
| f.write(string.Template(template).substitute(translations)) |
| else: |
| translations['array_size_element_format'] = self.array_size_element.public_format |
| template = ( |
| '${lp} ${array_size_element_format} ${common_var_prefix}_n_items;\n') |
| |
| if self.array_sequence_element != '': |
| translations['array_sequence_element_format'] = self.array_sequence_element.public_format |
| template += ( |
| '${lp} ${array_sequence_element_format} ${common_var_prefix}_sequence;\n') |
| |
| template += ( |
| '\n' |
| '${lp} /* Read number of items in the array */\n') |
| f.write(string.Template(template).substitute(translations)) |
| self.array_size_element.emit_buffer_read(f, line_prefix + ' ', common_var_prefix + '_n_items', buffer_name, buffer_len) |
| |
| if self.array_sequence_element != '': |
| template = ( |
| '\n' |
| '${lp} /* Read sequence in the array */\n') |
| f.write(string.Template(template).substitute(translations)) |
| self.array_size_element.emit_buffer_read(f, line_prefix + ' ', common_var_prefix + '_sequence', buffer_name, buffer_len) |
| |
| template = ( |
| '\n' |
| '${lp} ${variable_name}_sequence = ${common_var_prefix}_sequence;\n') |
| f.write(string.Template(template).substitute(translations)) |
| |
| |
| template = ( |
| '\n' |
| '${lp} ${variable_name} = g_array_sized_new (\n' |
| '${lp} FALSE,\n' |
| '${lp} FALSE,\n' |
| '${lp} sizeof (${public_array_element_format}),\n' |
| '${lp} (guint)${common_var_prefix}_n_items);\n' |
| '\n') |
| |
| if self.array_element.needs_dispose == True: |
| template += ( |
| '${lp} g_array_set_clear_func (${variable_name},\n' |
| '${lp} (GDestroyNotify)${underscore}_clear);\n' |
| '\n') |
| |
| template += ( |
| '${lp} for (${common_var_prefix}_i = 0; ${common_var_prefix}_i < ${common_var_prefix}_n_items; ${common_var_prefix}_i++) {\n' |
| '${lp} ${public_array_element_format} ${common_var_prefix}_aux;\n' |
| '\n') |
| f.write(string.Template(template).substitute(translations)) |
| |
| self.array_element.emit_buffer_read(f, line_prefix + ' ', common_var_prefix + '_aux', buffer_name, buffer_len) |
| |
| template = ( |
| '${lp} g_array_insert_val (${variable_name}, ${common_var_prefix}_i, ${common_var_prefix}_aux);\n' |
| '${lp} }\n' |
| '${lp}}\n') |
| f.write(string.Template(template).substitute(translations)) |
| |
| |
| """ |
| Emits the code involved in computing the size of the variable. |
| """ |
| def emit_size_read(self, f, line_prefix, variable_name, buffer_name, buffer_len): |
| common_var_prefix = utils.build_underscore_name(self.name) |
| translations = { 'lp' : line_prefix, |
| 'variable_name' : variable_name, |
| 'buffer_name' : buffer_name, |
| 'buffer_len' : buffer_len, |
| 'common_var_prefix' : common_var_prefix } |
| |
| template = ( |
| '${lp}{\n' |
| '${lp} guint ${common_var_prefix}_i;\n' |
| '\n') |
| f.write(string.Template(template).substitute(translations)) |
| |
| if self.fixed_size: |
| translations['fixed_size'] = self.fixed_size |
| |
| template = ( |
| '${lp} guint16 ${common_var_prefix}_n_items = ${fixed_size};\n') |
| f.write(string.Template(template).substitute(translations)) |
| else: |
| translations['array_size_element_format'] = self.array_size_element.public_format |
| if self.array_size_element.public_format == 'guint8': |
| translations['array_size_element_size'] = '1' |
| elif self.array_size_element.public_format == 'guint16': |
| translations['array_size_element_size'] = '2' |
| elif self.array_size_element.public_format == 'guint32': |
| translations['array_size_element_size'] = '4' |
| else: |
| translations['array_size_element_size'] = '0' |
| |
| template = ( |
| '${lp} ${array_size_element_format} ${common_var_prefix}_n_items;\n' |
| '${lp} const guint8 *${common_var_prefix}_aux_buffer = &${buffer_name}[${variable_name}];\n' |
| '${lp} guint16 ${common_var_prefix}_aux_buffer_len = ${buffer_len} - ${variable_name};\n' |
| '\n' |
| '${lp} ${variable_name} += ${array_size_element_size};\n') |
| |
| if self.array_sequence_element != '': |
| if self.array_sequence_element.public_format == 'guint8': |
| translations['array_sequence_element_size'] = '1' |
| elif self.array_sequence_element.public_format == 'guint16': |
| translations['array_sequence_element_size'] = '2' |
| elif self.array_sequence_element.public_format == 'guint32': |
| translations['array_sequence_element_size'] = '4' |
| else: |
| translations['array_sequence_element_size'] = '0' |
| template += ( |
| '\n' |
| '${lp} ${variable_name} += ${array_sequence_element_size};\n') |
| |
| f.write(string.Template(template).substitute(translations)) |
| |
| self.array_size_element.emit_buffer_read(f, line_prefix + ' ', common_var_prefix + '_n_items', common_var_prefix + '_aux_buffer', common_var_prefix + '_aux_buffer_len') |
| |
| template = ( |
| '\n' |
| '${lp} for (${common_var_prefix}_i = 0; ${common_var_prefix}_i < ${common_var_prefix}_n_items; ${common_var_prefix}_i++) {\n' |
| '\n') |
| f.write(string.Template(template).substitute(translations)) |
| |
| self.array_element.emit_size_read(f, line_prefix + ' ', variable_name, buffer_name, buffer_len) |
| |
| template = ( |
| '${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): |
| common_var_prefix = utils.build_underscore_name(self.name) |
| translations = { 'lp' : line_prefix, |
| 'variable_name' : variable_name, |
| 'buffer_name' : buffer_name, |
| 'buffer_len' : buffer_len, |
| 'common_var_prefix' : common_var_prefix } |
| |
| template = ( |
| '${lp}{\n' |
| '${lp} guint ${common_var_prefix}_i;\n') |
| f.write(string.Template(template).substitute(translations)) |
| |
| if self.fixed_size == 0: |
| translations['array_size_element_format'] = self.array_size_element.private_format |
| |
| template = ( |
| '${lp} ${array_size_element_format} ${common_var_prefix}_n_items;\n' |
| '\n' |
| '${lp} /* Write the number of items in the array first */\n' |
| '${lp} ${common_var_prefix}_n_items = (${array_size_element_format}) ${variable_name}->len;\n') |
| f.write(string.Template(template).substitute(translations)) |
| |
| self.array_size_element.emit_buffer_write(f, line_prefix + ' ', common_var_prefix + '_n_items', buffer_name, buffer_len) |
| |
| if self.array_sequence_element != '': |
| self.array_sequence_element.emit_buffer_write(f, line_prefix + ' ', variable_name + '_sequence', buffer_name, buffer_len) |
| |
| |
| template = ( |
| '\n' |
| '${lp} for (${common_var_prefix}_i = 0; ${common_var_prefix}_i < ${variable_name}->len; ${common_var_prefix}_i++) {\n') |
| f.write(string.Template(template).substitute(translations)) |
| |
| self.array_element.emit_buffer_write(f, line_prefix + ' ', 'g_array_index (' + variable_name + ', ' + self.array_element.public_format + ',' + common_var_prefix + '_i)', buffer_name, buffer_len) |
| |
| template = ( |
| '${lp} }\n' |
| '${lp}}\n') |
| f.write(string.Template(template).substitute(translations)) |
| |
| |
| """ |
| 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): |
| common_var_prefix = utils.build_underscore_name(self.name) |
| translations = { 'lp' : line_prefix, |
| 'printable' : printable, |
| 'buffer_name' : buffer_name, |
| 'buffer_len' : buffer_len, |
| 'common_var_prefix' : common_var_prefix } |
| |
| template = ( |
| '${lp}{\n' |
| '${lp} guint ${common_var_prefix}_i;\n') |
| f.write(string.Template(template).substitute(translations)) |
| |
| if self.fixed_size: |
| translations['fixed_size'] = self.fixed_size |
| |
| template = ( |
| '${lp} guint16 ${common_var_prefix}_n_items = ${fixed_size};\n' |
| '\n') |
| f.write(string.Template(template).substitute(translations)) |
| else: |
| translations['array_size_element_format'] = self.array_size_element.public_format |
| template = ( |
| '${lp} ${array_size_element_format} ${common_var_prefix}_n_items;\n') |
| |
| if self.array_sequence_element != '': |
| translations['array_sequence_element_format'] = self.array_sequence_element.public_format |
| template += ( |
| '${lp} ${array_sequence_element_format} ${common_var_prefix}_sequence;\n') |
| |
| template += ( |
| '\n' |
| '${lp} /* Read number of items in the array */\n') |
| f.write(string.Template(template).substitute(translations)) |
| self.array_size_element.emit_buffer_read(f, line_prefix + ' ', common_var_prefix + '_n_items', buffer_name, buffer_len) |
| |
| if self.array_sequence_element != '': |
| template = ( |
| '\n' |
| '${lp} /* Read sequence */\n') |
| f.write(string.Template(template).substitute(translations)) |
| self.array_sequence_element.emit_buffer_read(f, line_prefix + ' ', common_var_prefix + '_sequence', buffer_name, buffer_len) |
| template = ( |
| '\n' |
| '${lp} g_string_append_printf (${printable}, "[[Seq:%u]] ", ${common_var_prefix}_sequence);\n') |
| f.write(string.Template(template).substitute(translations)) |
| |
| template = ( |
| '\n' |
| '${lp} g_string_append (${printable}, "{");\n' |
| '\n' |
| '${lp} for (${common_var_prefix}_i = 0; ${common_var_prefix}_i < ${common_var_prefix}_n_items; ${common_var_prefix}_i++) {\n' |
| '${lp} g_string_append_printf (${printable}, " [%u] = \'", ${common_var_prefix}_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)) |
| |
| |
| """ |
| Variable declaration |
| """ |
| def build_variable_declaration(self, line_prefix, variable_name): |
| translations = { 'lp' : line_prefix, |
| 'name' : variable_name } |
| |
| template = '' |
| if self.array_sequence_element != '': |
| translations['array_sequence_element_format'] = self.array_sequence_element.public_format |
| template += ( |
| '${lp}${array_sequence_element_format} ${name}_sequence;\n') |
| |
| template += ( |
| '${lp}GArray *${name};\n') |
| return string.Template(template).substitute(translations) |
| |
| |
| """ |
| Getter for the array type |
| """ |
| def build_getter_declaration(self, line_prefix, variable_name): |
| translations = { 'lp' : line_prefix, |
| 'name' : variable_name } |
| |
| template = '' |
| if self.array_sequence_element != '': |
| translations['array_sequence_element_format'] = self.array_sequence_element.public_format |
| template += ( |
| '${lp}${array_sequence_element_format} *${name}_sequence,\n') |
| |
| template += ( |
| '${lp}GArray **${name},\n') |
| return string.Template(template).substitute(translations) |
| |
| |
| """ |
| Documentation for the getter |
| """ |
| def build_getter_documentation(self, line_prefix, variable_name): |
| translations = { 'lp' : line_prefix, |
| 'public_array_element_format' : self.array_element.public_format, |
| 'name' : variable_name } |
| |
| template = '' |
| if self.array_sequence_element != '': |
| template += ( |
| '${lp}@${name}_sequence: a placeholder for the output sequence number, or %NULL if not required.\n') |
| |
| template += ( |
| '${lp}@${name}: a placeholder for the output #GArray of #${public_array_element_format} elements, or %NULL if not required. Do not free it, it is owned by @self.\n') |
| return string.Template(template).substitute(translations) |
| |
| |
| """ |
| Builds the array getter implementation |
| """ |
| def build_getter_implementation(self, line_prefix, variable_name_from, variable_name_to, to_is_reference): |
| translations = { 'lp' : line_prefix, |
| 'from' : variable_name_from, |
| 'to' : variable_name_to } |
| |
| template = '' |
| if self.array_sequence_element != '': |
| template += ( |
| '${lp}if (${to}_sequence)\n' |
| '${lp} *${to}_sequence = ${from}_sequence;\n') |
| |
| if to_is_reference: |
| template += ( |
| '${lp}if (${to})\n' |
| '${lp} *${to} = ${from};\n') |
| else: |
| template += ( |
| '${lp}${to} = ${from};\n') |
| |
| return string.Template(template).substitute(translations) |
| |
| |
| """ |
| Setter for the array type |
| """ |
| def build_setter_declaration(self, line_prefix, variable_name): |
| translations = { 'lp' : line_prefix, |
| 'name' : variable_name } |
| |
| template = '' |
| if self.array_sequence_element != '': |
| translations['array_sequence_element_format'] = self.array_sequence_element.public_format |
| template += ( |
| '${lp}${array_sequence_element_format} ${name}_sequence,\n') |
| |
| template += ( |
| '${lp}GArray *${name},\n') |
| return string.Template(template).substitute(translations) |
| |
| |
| """ |
| Documentation for the setter |
| """ |
| def build_setter_documentation(self, line_prefix, variable_name): |
| translations = { 'lp' : line_prefix, |
| 'public_array_element_format' : self.array_element.public_format, |
| 'name' : variable_name } |
| |
| template = '' |
| if self.array_sequence_element != '': |
| template += ( |
| '${lp}@${name}_sequence: the sequence number.\n') |
| |
| template += ( |
| '${lp}@${name}: a #GArray of #${public_array_element_format} elements. A new reference to @${name} will be taken.\n') |
| return string.Template(template).substitute(translations) |
| |
| |
| """ |
| Builds the array setter implementation |
| """ |
| def build_setter_implementation(self, line_prefix, variable_name_from, variable_name_to): |
| translations = { 'lp' : line_prefix, |
| 'from' : variable_name_from, |
| 'to' : variable_name_to } |
| |
| template = '' |
| if self.array_sequence_element != '': |
| template += ( |
| '${lp}${to}_sequence = ${from}_sequence;\n') |
| |
| template += ( |
| '${lp}if (${to})\n' |
| '${lp} g_array_unref (${to});\n' |
| '${lp}${to} = g_array_ref (${from});\n') |
| return string.Template(template).substitute(translations) |
| |
| |
| """ |
| Documentation for the struct field |
| """ |
| def build_struct_field_documentation(self, line_prefix, variable_name): |
| translations = { 'lp' : line_prefix, |
| 'public_array_element_format' : self.array_element.public_format, |
| 'name' : variable_name } |
| |
| template = '' |
| if self.array_sequence_element != '': |
| template += ( |
| '${lp}@${name}_sequence: the sequence number.\n') |
| |
| template += ( |
| '${lp}@${name}: a #GArray of #${public_array_element_format} elements.\n') |
| return string.Template(template).substitute(translations) |
| |
| |
| """ |
| Dispose the array just with an unref |
| """ |
| def build_dispose(self, line_prefix, variable_name): |
| translations = { 'lp' : line_prefix, |
| 'variable_name' : variable_name } |
| |
| template = ( |
| '${lp}if (${variable_name})\n' |
| '${lp} g_array_unref (${variable_name});\n') |
| return string.Template(template).substitute(translations) |
| |
| |
| """ |
| Add sections |
| """ |
| def add_sections(self, sections): |
| self.array_element.add_sections(sections) |