yet another defs extractor script



Attached is a small script that can be used to use the introspection features of libgobject to extract some defs from a library. It takes a file with a list of types and includes (similar to the input file for gtkdoc-scanobj), and outputs various definitions:
 object defs (with correct implements lines)
 interface defs
 boxed defs
 enum and flag defs
 signal defs
 property defs

It uses pkg-config to work out how to link with the library. An example of its use:
 $ cat > gtk-types << EOF
 #include <gtk/gtk.h>
 GDK_TYPE_CURSOR_TYPE
 GDK_TYPE_EVENT_MASK
 GTK_TYPE_WINDOW_TYPE
 GTK_TYPE_OBJECT
 GTK_TYPE_WIDGET
 GTK_TYPE_TREE_MODEL
 GTK_TYPE_TREE_STORE
 GTK_TYPE_TREE_ITER
 EOF
$ python extract.py -m gtk+-2.0 -t gtk-types --type-init-func='gtk_type_init(0);'

This will print out the definitions related to the given types. The program creates a simple C program, which is compiled and run. The output of this program is the definitions related to those types.

It could probably be modified to scan a set of headers for types to examine.

James.

--
Email: james daa com au
WWW:   http://www.daa.com.au/~james/

import sys, os, string, getopt

# handlers for writing out information gained through introspection

usage = 'usage: extract -m pkgconfigmodule -t typesfile [ --type-init-func func ]\n'
help = usage + \
'''Extract defs info from a library via introspection

  -m, --module=MODULE         a pkg-config module name (for compiler flags)
  -t, --types=TYPESFILE       a file containing the list of types to check
      --type-init-func=FUNC   a function called to initialise types

The types file can contain #include directives needed to access the
types.  Other lines are treated as type ids (eg. GTK_TYPE_WIDGET) to
parse.

The output will be a list of definitions for various things that can
be accessed at runtime.
'''

handlers = r'''

typedef void (* InfoWriterFunc)(GType type, const gchar *gtypeid);

static const gchar *
get_name(GType type)
{
    const gchar *type_name;

    type_name = g_type_name(type);
    while (*(++type_name) != '\0') {
        if (g_ascii_isupper(type_name[0]))
            return type_name;
    }
    return g_type_name(type);
}

static void
print_module(GType type)
{
    gchar *type_name, *p;

    type_name = g_strdup(g_type_name(type));
    p = type_name;
    while (*(++p) != '\0') {
        if (g_ascii_isupper(*p)) {
            *p = '\0';
            break;
        }
    }
    printf("  (in-module \"%s\")\n", type_name);
    g_free(type_name);
}

static void
write_signal_info(GType type, const gchar *gtypeid)
{
    GTypeClass *tclass = NULL;
    guint *signal_ids, n_signals = 0, i;

    if (!G_TYPE_IS_INSTANTIATABLE(type) && !G_TYPE_IS_INTERFACE(type))
        return;

    if (G_TYPE_IS_CLASSED(type))
        tclass = g_type_class_ref(type);

    signal_ids = g_signal_list_ids(type, &n_signals);
    for (i = 0; i < n_signals; i++) {
        GSignalQuery query;

        g_signal_query(signal_ids[i], &query);

        printf("(define-signal \"%s\"\n", query.signal_name);
        printf("  (of-object \"%s\")\n", g_type_name(type));
        printf("  (return-type \"%s\")\n", g_type_name(query.return_type));
        if ((query.signal_flags & G_SIGNAL_RUN_FIRST) &&
            (query.signal_flags & G_SIGNAL_RUN_LAST)) {
            printf("  (when \"both\")\n");
        } else if (query.signal_flags & G_SIGNAL_RUN_FIRST) {
            printf("  (when \"first\")\n");
        } else if (query.signal_flags & G_SIGNAL_RUN_LAST) {
            printf("  (when \"last\")\n");
        }
        if (query.n_params > 0) {
            guint j;

            printf("  (parameters\n");
            for (j = 0; j < query.n_params; j++) {
                printf("    '(\"%s\" \"arg%d\"", g_type_name(query.param_types[j] & ~G_SIGNAL_TYPE_STATIC_SCOPE), j);
                if (query.param_types[j] & G_SIGNAL_TYPE_STATIC_SCOPE)
                    printf(" \"static-scope\"");
                printf(")\n");
            }
            printf("  )\n");
        }
        printf(")\n\n");
    }
    g_free(signal_ids);

    if (tclass)
        g_type_class_unref(tclass);
}

static void
write_property_info(GType type, const gchar *gtypeid)
{
    GObjectClass *oclass = NULL;
    GParamSpec **properties;
    guint n_properties = 0, i;

    if (!G_TYPE_IS_OBJECT(type))
        return;

    oclass = g_type_class_ref(type);
    properties = g_object_class_list_properties(oclass, &n_properties);
    for (i = 0; i < n_properties; i++) {
        printf("(define-property \"%s\"\n",
               g_param_spec_get_name(properties[i]));
        printf("  (of-object \"%s\")\n", g_type_name(type));
        printf("  (prop-type \"%s\")\n",
               g_type_name(properties[i]->value_type));
        printf("  (readable %s)\n",
               (properties[i]->flags & G_PARAM_READABLE) ? "#t" : "#f");
        printf("  (writable %s)\n",
               (properties[i]->flags & G_PARAM_WRITABLE) ? "#t" : "#f");
        printf("  (construct-only %s)\n",
               (properties[i]->flags & G_PARAM_CONSTRUCT_ONLY) ? "#t" : "#f");
        printf(")\n\n");
    }
    g_free(properties);
    g_type_class_unref(oclass);
}

static void
write_enum_info(GType type, const gchar *gtypeid)
{
    GEnumClass *eclass;
    guint i;

    if (!G_TYPE_IS_ENUM(type))
        return;
    eclass = g_type_class_ref(type);

    printf("(define-enum \"%s\"\n", get_name(type));
    print_module(type);
    printf("  (c-name \"%s\")\n", g_type_name(type));
    printf("  (gtype-id \"%s\")\n", gtypeid);
    printf("  (values\n");
    for (i = 0; i < eclass->n_values; i++) {
        printf("    '(\"%s\" \"%s\" %d)\n", eclass->values[i].value_nick, 
               eclass->values[i].value_name, eclass->values[i].value);
    }
    printf("  )\n");
    printf(")\n\n");

    g_type_class_unref(eclass);
}

static void
write_flags_info(GType type, const gchar *gtypeid)
{
    GFlagsClass *fclass;
    guint i;

    if (!G_TYPE_IS_FLAGS(type))
        return;
    fclass = g_type_class_ref(type);

    printf("(define-flags \"%s\"\n", get_name(type));
    print_module(type);
    printf("  (c-name \"%s\")\n", g_type_name(type));
    printf("  (gtype-id \"%s\")\n", gtypeid);
    printf("  (values\n");
    for (i = 0; i < fclass->n_values; i++) {
        printf("    '(\"%s\" \"%s\" %u)\n", fclass->values[i].value_nick,
               fclass->values[i].value_name, fclass->values[i].value);
    }
    printf("  )\n");
    printf(")\n\n");

    g_type_class_unref(fclass);
}

static void
write_interface_info(GType type, const gchar *gtypeid)
{
    if (!G_TYPE_IS_INTERFACE(type))
        return;

    printf("(define-interface \"%s\"\n", get_name(type));
    print_module(type);
    printf("  (c-name \"%s\")\n", g_type_name(type));
    printf("  (gtype-id \"%s\")\n", gtypeid);
    printf(")\n\n");
}

static void
write_object_info(GType type, const gchar *gtypeid)
{
    GType *interfaces;
    guint n_interfaces = 0, i;

    if (!G_TYPE_IS_OBJECT(type))
        return;

    printf("(define-object \"%s\"\n", get_name(type));
    print_module(type);
    if (g_type_parent(type) != G_TYPE_INVALID)
        printf("  (parent \"%s\")\n", g_type_name(g_type_parent(type)));
    printf("  (c-name \"%s\")\n", g_type_name(type));
    printf("  (gtype-id \"%s\")\n", gtypeid);
    interfaces = g_type_interfaces(type, &n_interfaces);
    for (i = 0; i < n_interfaces; i++)
        printf("  (implements \"%s\")\n", g_type_name(interfaces[i]));
    g_free(interfaces);
    printf(")\n\n");
}

static void
write_boxed_info(GType type, const gchar *gtypeid)
{
    if (!G_TYPE_IS_BOXED(type))
        return;

    printf("(define-boxed \"%s\"\n", get_name(type));
    print_module(type);
    printf("  (c-name \"%s\")\n", g_type_name(type));
    printf("  (gtype-id \"%s\")\n", gtypeid);
    printf(")\n\n");
}
'''

main_func = r'''
int
main(int argc, char **argv)
{
    g_type_init();
    %(typeinit)s

    printf(";; -*- mode: scheme -*-\n\n");
    printf(";; --------- type defs ---------\n");
    foreach_type(write_interface_info);
    foreach_type(write_object_info);
    foreach_type(write_boxed_info);
    printf("\n");

    printf(";; --------- enum and flags defs ---------\n");
    foreach_type(write_enum_info);
    foreach_type(write_flags_info);
    printf("\n");

    printf(";; --------- property defs ---------\n");
    foreach_type(write_property_info);
    printf("\n");

    printf(";; --------- signal defs ---------\n");
    foreach_type(write_signal_info);
    printf("\n");

    return 0;
}
'''

def read_types_file(fp):
    '''returns (types, includes)'''
    types = []
    includes = []
    for line in fp.readlines():
        line = string.strip(line)
        if not line: continue
        if line[0] == '#':
            includes.append(line)
        else:
            types.append(line)
    return (types, includes)

def write_check_prog(fp, types, includes, type_init=''):
    fp.write("/* -*- mode: C; c-basic-offset: 4 -*- */\n")
    fp.write("#include <glib-object.h>\n")
    for line in includes:
        fp.write(line + '\n')

    # write out the handlers
    fp.write(handlers)

    # write out the function to iterate over types
    fp.write("static void\nforeach_type(InfoWriterFunc func)\n{\n")
    for type in types:
        fp.write("    func(%s, \"%s\");\n" % (type, type))
    fp.write("}\n\n")

    fp.write(main_func % { 'typeinit': type_init })

def main():
    module = None
    typesfile = None
    type_init = ''
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'm:t:',
                                   ['module=', 'types=', 'type-init-func=', 'help'])
    except getopt.error, msg:
        sys.stderr.write('extract: %s\n' % msg)
        sys.stderr.write(usage)
        sys.exit(1)
    for opt, arg in opts:
        if opt in ('-m', '--module'):
            module = arg
        elif opt in ('-t', '--types'):
            typesfile = arg
        elif opt in ('--type-init-func',):
            type_init = arg
        elif opt in ('--help',):
            sys.stdout.write(help)
            sys.exit(0)
    if len(args) > 0:
        sys.stderr.write('extract: no extra args expected\n')
        sys.stderr.write(usage)
        sys.exit(1)
    if not module or not typesfile:
        sys.stderr.write('extrace: required argument missing\n')
        sys.stderr.write(usage)
        sys.exit(1)

    # read the type names to work with
    types, includes = read_types_file(open(typesfile, 'r'))

    # use pkg-config to work out what flags to use
    cflags = string.strip(os.popen('pkg-config --cflags ' + module).read())
    libs = string.strip(os.popen('pkg-config --libs ' + module).read())

    # write the test program
    write_check_prog(open('__extract.c', 'w'),
                     types, includes, type_init)

    # compile the program
    os.system('cc %s -o __extract __extract.c %s' % (cflags, libs))

    # run the program
    os.system('./__extract')

    os.unlink('__extract')
    os.unlink('__extract.c')

if __name__ == '__main__':
    main()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]