#!/bin/env python # -*- Mode: Python -*- # GObject-Introspection - a framework for introspecting GObject libraries # Copyright (C) 2008 Red Hat, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU 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 General Public License for more details. # # You should have received a copy of the GNU 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. # # The idea here is that we want to compare offset information two ways: # # 1) As generated by the compiler # 2) As found in the typelib # # So we find all the structures in the input file (offsets.h), parse out # fields within the structure and generate code that outputs the field # offsets using G_STRUCT_OFFSET() to one file and the field offsets using # the typelib to the another file. We can then diff the two files to see # if they are the same import re import sys if len(sys.argv) != 2: print >>sys.stderr, "Usage: gen-gitestoffsets INPUT > OUTPUT" sys.exit(1) # Helper function that we use to generate source. It does substitions # from a dictionary, removes white space at the ends and removes a # leading '|' from each line STRIP_AROUND_RE = re.compile("^[ \t]*\n?(.*?)[ \t]*$", re.DOTALL) STRIP_LEADER_RE = re.compile("^\|", re.MULTILINE) def output(args, format): format = STRIP_AROUND_RE.sub(r"\1", format) format = STRIP_LEADER_RE.sub(r"", format) sys.stdout.write(format % args) # # Some regular expressions we use when parsing # TOKEN = "(?:[A-Za-z_][A-Za-z_0-9]+)" def compile_re(expr): expr = expr.replace("TOKEN", TOKEN) return re.compile(expr, re.VERBOSE) COMMENT_RE = compile_re("/\*([^*]+|\*[^/])*\*/") STRUCT_DEF_RE = compile_re("struct\s+_(TOKEN)\s*{([^}]*)}") # This certainly can't handle all type declarations, but it only # needs to handle the ones we use in the test cases FIELD_RE = compile_re(r"^(?:const\s+)?TOKEN(?:[\s*]+)(TOKEN)\s*(?:\[([0-9]*)\])?\s*;$") input_f = open(sys.argv[1]) input = input_f.read() input_f.close() # Strip comments input = COMMENT_RE.sub("", input) symbols = [] symbol_fields = {} for m in STRUCT_DEF_RE.finditer(input): symbol = m.group(1) fields = [] body = m.group(2) for line in re.split("\n|\r\n", body): line = line.strip() if line == "": continue n = FIELD_RE.match(line) if not n: print sys.stderr, "Can't parse structure line '%s'" % line sys.exit(1) fields.append(n.group(1)) symbols.append(symbol) symbol_fields[symbol] = fields # Sort for convenience symbols.sort() output({}, r''' | /* GENERATED FILE. DO NOT EDIT. See gen-gitestoffsets */ | |#include |#include |#include |#include |#include |#include "offsets.h" | |static GIRepository *repository; |static const char *namespace = "Offsets"; |static const char *version = "1.0"; | |static void |print_field_offset(FILE *outfile, | GIStructInfo *struct_info, | const gchar *name) |{ | gint i; | gint n_fields = g_struct_info_get_n_fields (struct_info); | for (i = 0; i < n_fields; i++) | { | GIFieldInfo *field_info = g_struct_info_get_field (struct_info, i); | const char *field_name = g_base_info_get_name ((GIBaseInfo *)field_info); | if (strcmp (field_name, name) == 0) | { | fprintf (outfile, "%%s %%d\n", name, g_field_info_get_offset (field_info)); | g_base_info_unref ((GIBaseInfo *)field_info); | return; | } | | g_base_info_unref ((GIBaseInfo *)field_info); | } | | g_error("Can't find field '%%s.%%s' in introspection information", | g_base_info_get_name ((GIBaseInfo *)struct_info), name); |} | ''') for symbol in symbols: fields = symbol_fields[symbol] output({'symbol' : symbol}, r''' |typedef struct { | char dummy; | %(symbol)s struct_; |} Align%(symbol)s; | |static void |compiled_%(symbol)s (FILE *outfile) |{ | fprintf (outfile, "%(symbol)s: size=%%" G_GSIZE_FORMAT ", alignment=%%ld\n", | sizeof(%(symbol)s), | G_STRUCT_OFFSET(Align%(symbol)s, struct_)); | ''') for field in fields: output({ 'field' : field, 'symbol' : symbol }, r''' | fprintf (outfile, "%%s %%ld\n", "%(field)s", G_STRUCT_OFFSET(%(symbol)s, %(field)s)); ''') output({}, r''' | | fprintf (outfile, "\n"); |} | ''') if not symbol.startswith("Offsets"): print >> sys.stderr, "Symbol '%s' doesn't start with Offsets" % symbol bare_symbol = symbol[len("Offsets"):] output({'symbol' : symbol, 'bare_symbol' : bare_symbol}, r''' |static void |introspected_%(symbol)s (FILE *outfile) |{ | GIStructInfo *struct_info = (GIStructInfo *)g_irepository_find_by_name(repository, namespace, | "%(bare_symbol)s"); | if (!struct_info) | g_error ("Can't find GIStructInfo for '%(symbol)s'"); | | fprintf (outfile, "%(symbol)s: size=%%" G_GSIZE_FORMAT ", alignment=%%" G_GSIZE_FORMAT "\n", | g_struct_info_get_size (struct_info), | g_struct_info_get_alignment (struct_info)); | ''') for field in fields: output({'field' : field}, ''' | print_field_offset(outfile, struct_info, "%(field)s"); ''') output({}, r''' | | fprintf (outfile, "\n"); | | g_base_info_unref ((GIBaseInfo *)struct_info); |} ''') output({}, r''' | |int main(int argc, char **argv) |{ | GError *error = NULL; | FILE *outfile; | | if (argc != 3) | g_error ("Usage: gitestoffsets COMPILED_OFFSETS_FILE INTROSPECTED_OFFSETS_FILE"); | | repository = g_irepository_get_default (); | if (!g_irepository_require (repository, namespace, version, 0, &error)) | g_error ("Failed to load %%s-%%s.typelib: %%s", namespace, version, error->message); | | outfile = fopen (argv[1], "w"); | if (!outfile) | g_error ("Cannot open '%%s': %%s'", argv[1], g_strerror(errno)); | ''') for symbol in symbols: output({'symbol' : symbol}, ''' | compiled_%(symbol)s (outfile); ''') output({}, ''' | | fclose (outfile); | | outfile = fopen (argv[2], "w"); | if (!outfile) | g_error ("Cannot open '%%s': %%s'", argv[1], g_strerror(errno)); | ''') for symbol in symbols: output({'symbol' : symbol}, ''' | introspected_%(symbol)s (outfile); ''') output({}, r''' | | fclose (outfile); | | return 0; } ''')