From 555368639b86248ef7f737dfdcc55f3ceeaba7b2 Mon Sep 17 00:00:00 2001 From: Markus Teich Date: Tue, 3 Feb 2015 23:33:42 +0100 Subject: [PATCH 1/2] python generator for capi interface stubs --- cef/base.c | 83 ++++++++++++++++++++++ cef/base.h | 23 +++++++ gen.c | 65 ++++++++++++++++++ implement_interface.py | 151 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 322 insertions(+) create mode 100644 cef/base.c create mode 100644 cef/base.h create mode 100644 gen.c create mode 100755 implement_interface.py diff --git a/cef/base.c b/cef/base.c new file mode 100644 index 0000000..1193108 --- /dev/null +++ b/cef/base.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +#include "cef/base.h" +#include "include/capi/cef_base_capi.h" + +CEF_CALLBACK void add_ref(struct _cef_base_t* self) +{ + struct refcount *r; + char *cp; + + cp = (char*)self; + cp -= sizeof(struct refcount); + r = (struct refcount*)cp; + + if ((errno = pthread_mutex_lock(&r->lock))) { + printf("failed to lock mutex"); + return; + } + r->refs++; + if ((errno = pthread_mutex_unlock(&r->lock))) { + printf("failed to unlock mutex"); + } +} + +CEF_CALLBACK int release(struct _cef_base_t* self) +{ + struct refcount *r; + char *cp; + + cp = (char*)self; + cp -= sizeof(struct refcount); + r = (struct refcount*)cp; + + if ((errno = pthread_mutex_lock(&r->lock))) { + printf("failed to lock mutex"); + return 0; + } + if (0 == --(r->refs)) { + pthread_mutex_unlock(&r->lock); + pthread_mutex_destroy(&r->lock); + free(r); + return 1; + } + if ((errno = pthread_mutex_unlock(&r->lock))) { + printf("failed to unlock mutex"); + } + return 0; +} + +CEF_CALLBACK int has_one_ref(struct _cef_base_t* self) +{ + struct refcount *r; + char *cp; + + cp = (char*)self; + cp -= sizeof(struct refcount); + r = (struct refcount*)cp; + + return r->refs == 1; +} + +int init_base(struct _cef_base_t* self, size_t sz) +{ + struct refcount *r; + char *cp; + + cp = (char*)self; + cp -= sizeof(struct refcount); + r = (struct refcount*)cp; + + if ((errno = pthread_mutex_init(&r->lock, NULL))) { + printf("failed to init mutex"); + return 0; + } + self->size = sz; + self->add_ref = &add_ref; + self->release = &release; + self->has_one_ref = &has_one_ref; + return 1; +} diff --git a/cef/base.h b/cef/base.h new file mode 100644 index 0000000..8af1c74 --- /dev/null +++ b/cef/base.h @@ -0,0 +1,23 @@ +#ifndef _CEFCAPI_BASE_H +#define _CEFCAPI_BASE_H + +#include +#include "include/capi/cef_base_capi.h" + +// increment/decrement refcounters +#define RINC(p) ((cef_base_t*)p)->add_ref((cef_base_t*)p) +#define RDEC(p) ((cef_base_t*)p)->release((cef_base_t*)p) + +#define DEBUG_ONCE(str) do{ static int first_call = 1; if (first_call) { first_call = 0; printf("debug_once: %s", str); } }while(0) + +struct refcount { + size_t refs; + pthread_mutex_t lock; +}; + +CEF_CALLBACK void add_ref(struct _cef_base_t* self); +CEF_CALLBACK int release(struct _cef_base_t* self); +CEF_CALLBACK int has_one_ref(struct _cef_base_t* self); +int init_base(struct _cef_base_t* self, size_t sz); + +#endif diff --git a/gen.c b/gen.c new file mode 100644 index 0000000..0ae2665 --- /dev/null +++ b/gen.c @@ -0,0 +1,65 @@ +#define __attribute__(x) +#include "include/capi/cef_app_capi.h" +#include "include/capi/cef_auth_callback_capi.h" +#include "include/capi/cef_base_capi.h" +#include "include/capi/cef_browser_capi.h" +#include "include/capi/cef_browser_process_handler_capi.h" +#include "include/capi/cef_callback_capi.h" +#include "include/capi/cef_client_capi.h" +#include "include/capi/cef_command_line_capi.h" +#include "include/capi/cef_context_menu_handler_capi.h" +#include "include/capi/cef_cookie_capi.h" +#include "include/capi/cef_dialog_handler_capi.h" +#include "include/capi/cef_display_handler_capi.h" +#include "include/capi/cef_dom_capi.h" +#include "include/capi/cef_download_handler_capi.h" +#include "include/capi/cef_download_item_capi.h" +#include "include/capi/cef_drag_data_capi.h" +#include "include/capi/cef_drag_handler_capi.h" +#include "include/capi/cef_focus_handler_capi.h" +#include "include/capi/cef_frame_capi.h" +#include "include/capi/cef_geolocation_capi.h" +#include "include/capi/cef_geolocation_handler_capi.h" +#include "include/capi/cef_jsdialog_handler_capi.h" +#include "include/capi/cef_keyboard_handler_capi.h" +#include "include/capi/cef_life_span_handler_capi.h" +#include "include/capi/cef_load_handler_capi.h" +#include "include/capi/cef_menu_model_capi.h" +#include "include/capi/cef_navigation_entry_capi.h" +#include "include/capi/cef_origin_whitelist_capi.h" +#include "include/capi/cef_path_util_capi.h" +#include "include/capi/cef_print_handler_capi.h" +#include "include/capi/cef_print_settings_capi.h" +#include "include/capi/cef_process_message_capi.h" +#include "include/capi/cef_process_util_capi.h" +#include "include/capi/cef_render_handler_capi.h" +#include "include/capi/cef_render_process_handler_capi.h" +#include "include/capi/cef_request_capi.h" +#include "include/capi/cef_request_context_capi.h" +#include "include/capi/cef_request_context_handler_capi.h" +#include "include/capi/cef_request_handler_capi.h" +#include "include/capi/cef_resource_bundle_handler_capi.h" +#include "include/capi/cef_resource_handler_capi.h" +#include "include/capi/cef_response_capi.h" +#include "include/capi/cef_scheme_capi.h" +#include "include/capi/cef_stream_capi.h" +#include "include/capi/cef_string_visitor_capi.h" +#include "include/capi/cef_task_capi.h" +#include "include/capi/cef_trace_capi.h" +#include "include/capi/cef_url_capi.h" +#include "include/capi/cef_urlrequest_capi.h" +#include "include/capi/cef_v8_capi.h" +#include "include/capi/cef_values_capi.h" +#include "include/capi/cef_web_plugin_capi.h" +#include "include/capi/cef_xml_reader_capi.h" +#include "include/capi/cef_zip_reader_capi.h" + +int foo(char* bar) +{ + return 0; +} + +int main(int argc, char** argv) +{ + return foo("bar"); +} diff --git a/implement_interface.py b/implement_interface.py new file mode 100755 index 0000000..eb32574 --- /dev/null +++ b/implement_interface.py @@ -0,0 +1,151 @@ +#!/bin/env python + +import sys +from pycparser import parse_file, c_generator, c_ast + +sys.path.extend(['.', '..']) + + +class StructVisitor(c_ast.NodeVisitor): + def visit_Struct(self, node): + try: + if not 'cef_base_t' in node.decls[0].type.type.names: + return + except AttributeError: + return + except TypeError: + return + + sname = node.name + fv = FuncDeclVisitor(sname[5:-1]) + fv.visit(node) + + hname = node.coord + + ret = [] + ret.append('/**********************************************************') + ret.append(' * BEWARE: This file is a autogenerated stub!') + ret.append(' *********************************************************/') + ret.append('') + ret.append('#include ') + ret.append('') + ret.append('#include "' + str(hname).lstrip('./').rstrip(':0123456789') + '"') + ret.append('') + ret.append('#include "cef/base.h"') + ret.append('#include "util.h"') + ret.append('') + ret.append('\n'.join(fv.ret)) + ret.append('struct ' + sname + ' *init_' + sname[5:-2] + '()') + ret.append('{') + ret.append('\tstruct ' + sname + ' *ret = NULL;') + ret.append('\tstruct refcount *r = NULL;') + ret.append('\tchar *cp = NULL;') + ret.append('') + ret.append('\tDEBUG_ONCE("init_' + sname[5:-2] + '() called");') + ret.append('\tif (!(r = calloc(sizeof(struct refcount) + sizeof(struct ' + sname + '), 1))) {') + ret.append('\t\tprintf("out of memory");') + ret.append('\t\treturn NULL;') + ret.append('\t}') + ret.append('') + ret.append('\tcp = (char*)r;') + ret.append('\tcp += sizeof(struct refcount);') + ret.append('\tret = (struct ' + sname + '*)cp;') + ret.append('') + ret.append('\tif(!init_base((cef_base_t*)ret, sizeof(struct ' + sname + '))) {') + ret.append('\t\tfree(r);') + ret.append('\t\treturn NULL;') + ret.append('\t}') + ret.append('\tret->base.add_ref((cef_base_t*)ret);') + ret.append('') + ret.append('\t// callbacks') + ret.append(fv.get_funlist()) + ret.append('') + ret.append('\treturn ret;') + ret.append('}') + + with open('cef/stubs/' + sname[5:-2] + '.c', 'w') as fh: + fh.write('\n'.join(ret).replace(' ', '\t').replace('\n\n\n', '\n\n')) + + +class FuncDeclVisitor(c_ast.NodeVisitor): + def __init__(self, sname): + self.sname = sname + self.gen = c_generator.CGenerator() + self.funs = {} + self.ret = [] + + def get_funlist(self): + return '\n'.join(['\tret->' + m + ' = &' + f + ';' for m, f in self.funs.items()]) + + def visit_FuncDecl(self, node): + try: + mfun = node.type.declname + fun = self.sname + mfun + node.type.declname = fun + rett = ' '.join(node.type.type.names) + except AttributeError: # This means the function returns a pointer + mfun = node.type.type.declname + fun = self.sname + mfun + node.type.type.declname = fun + rett = None + param = c_ast.Constant("string", '"' + fun + '() called"') + elist = c_ast.ExprList([param]) + call = c_ast.FuncCall(c_ast.ID('DEBUG_ONCE'), elist) + + compound = c_ast.Compound([call]) + + rval = { + 'int': c_ast.Constant("int", "0"), + 'int32': c_ast.Constant("int", "0"), + 'int64': c_ast.Constant("int", "0"), + 'uint32': c_ast.Constant("int", "0"), + 'size_t': c_ast.Constant("int", "0"), + 'double': c_ast.Constant("int", "0"), + 'unsigned long': c_ast.Constant("int", "0"), + # Enums... + 'cef_color_model_t': c_ast.Constant("int", "0"), + 'cef_context_menu_media_state_flags_t': c_ast.Constant("int", "0"), + 'cef_context_menu_media_type_t': c_ast.Constant("int", "0"), + 'cef_context_menu_type_flags_t': c_ast.Constant("int", "0"), + 'cef_context_menu_edit_state_flags_t': c_ast.Constant("int", "0"), + 'cef_dom_document_type_t': c_ast.Constant("int", "0"), + 'cef_dom_node_type_t': c_ast.Constant("int", "0"), + 'cef_duplex_mode_t': c_ast.Constant("int", "0"), + 'cef_errorcode_t': c_ast.Constant("int", "0"), + 'cef_menu_item_type_t': c_ast.Constant("int", "0"), + 'cef_postdataelement_type_t': c_ast.Constant("int", "0"), + 'cef_resource_type_t': c_ast.Constant("int", "0"), + 'cef_transition_type_t': c_ast.Constant("int", "0"), + 'cef_urlrequest_status_t': c_ast.Constant("int", "0"), + 'cef_value_type_t': c_ast.Constant("int", "0"), + 'cef_xml_node_type_t': c_ast.Constant("int", "0"), + # special cases... + 'time_t': c_ast.Constant("int", "0"), + 'cef_time_t': c_ast.Constant("Struct", "(cef_time_t){}"), + 'cef_string_userfree_t': c_ast.Constant("Ptr", "NULL"), + None: c_ast.Constant("Ptr", "NULL"), + }.get(rett, None) + if not rval is None: + ret = c_ast.Return(rval) + compound.block_items.append(ret) + elif rett != 'void': + print('Return type not handled: ' + rett) + sys.exit(1) + + decl = c_ast.Decl(fun, None, None, ["CEF_CALLBACK"], node, None, None) + fdef = c_ast.FuncDef(decl, None, compound) + + self.funs[mfun] = fun + # fix const double pointer: https://github.com/eliben/pycparser/issues/68 + self.ret.append(self.gen.visit(fdef).replace('* const ', ' const* ')) +# fdef.show() + + +if __name__ == "__main__": + if len(sys.argv) != 2: + sys.exit(1) + + ast = parse_file(sys.argv[1], use_cpp=True, cpp_args=[r'-Ifake', r'-I.']) + +# ast.show() + StructVisitor().visit(ast) From e0a540891aeea8d4658fff1ba757555657ecb1f8 Mon Sep 17 00:00:00 2001 From: Markus Teich Date: Sun, 8 Feb 2015 20:44:51 +0100 Subject: [PATCH 2/2] autogenerate bootstrap C source for implementor --- gen.c | 65 ------------------------------------------ implement_interface.py | 14 +++++++-- 2 files changed, 11 insertions(+), 68 deletions(-) delete mode 100644 gen.c diff --git a/gen.c b/gen.c deleted file mode 100644 index 0ae2665..0000000 --- a/gen.c +++ /dev/null @@ -1,65 +0,0 @@ -#define __attribute__(x) -#include "include/capi/cef_app_capi.h" -#include "include/capi/cef_auth_callback_capi.h" -#include "include/capi/cef_base_capi.h" -#include "include/capi/cef_browser_capi.h" -#include "include/capi/cef_browser_process_handler_capi.h" -#include "include/capi/cef_callback_capi.h" -#include "include/capi/cef_client_capi.h" -#include "include/capi/cef_command_line_capi.h" -#include "include/capi/cef_context_menu_handler_capi.h" -#include "include/capi/cef_cookie_capi.h" -#include "include/capi/cef_dialog_handler_capi.h" -#include "include/capi/cef_display_handler_capi.h" -#include "include/capi/cef_dom_capi.h" -#include "include/capi/cef_download_handler_capi.h" -#include "include/capi/cef_download_item_capi.h" -#include "include/capi/cef_drag_data_capi.h" -#include "include/capi/cef_drag_handler_capi.h" -#include "include/capi/cef_focus_handler_capi.h" -#include "include/capi/cef_frame_capi.h" -#include "include/capi/cef_geolocation_capi.h" -#include "include/capi/cef_geolocation_handler_capi.h" -#include "include/capi/cef_jsdialog_handler_capi.h" -#include "include/capi/cef_keyboard_handler_capi.h" -#include "include/capi/cef_life_span_handler_capi.h" -#include "include/capi/cef_load_handler_capi.h" -#include "include/capi/cef_menu_model_capi.h" -#include "include/capi/cef_navigation_entry_capi.h" -#include "include/capi/cef_origin_whitelist_capi.h" -#include "include/capi/cef_path_util_capi.h" -#include "include/capi/cef_print_handler_capi.h" -#include "include/capi/cef_print_settings_capi.h" -#include "include/capi/cef_process_message_capi.h" -#include "include/capi/cef_process_util_capi.h" -#include "include/capi/cef_render_handler_capi.h" -#include "include/capi/cef_render_process_handler_capi.h" -#include "include/capi/cef_request_capi.h" -#include "include/capi/cef_request_context_capi.h" -#include "include/capi/cef_request_context_handler_capi.h" -#include "include/capi/cef_request_handler_capi.h" -#include "include/capi/cef_resource_bundle_handler_capi.h" -#include "include/capi/cef_resource_handler_capi.h" -#include "include/capi/cef_response_capi.h" -#include "include/capi/cef_scheme_capi.h" -#include "include/capi/cef_stream_capi.h" -#include "include/capi/cef_string_visitor_capi.h" -#include "include/capi/cef_task_capi.h" -#include "include/capi/cef_trace_capi.h" -#include "include/capi/cef_url_capi.h" -#include "include/capi/cef_urlrequest_capi.h" -#include "include/capi/cef_v8_capi.h" -#include "include/capi/cef_values_capi.h" -#include "include/capi/cef_web_plugin_capi.h" -#include "include/capi/cef_xml_reader_capi.h" -#include "include/capi/cef_zip_reader_capi.h" - -int foo(char* bar) -{ - return 0; -} - -int main(int argc, char** argv) -{ - return foo("bar"); -} diff --git a/implement_interface.py b/implement_interface.py index eb32574..6f5b408 100755 --- a/implement_interface.py +++ b/implement_interface.py @@ -1,5 +1,6 @@ #!/bin/env python +import os import sys from pycparser import parse_file, c_generator, c_ast @@ -142,10 +143,17 @@ def visit_FuncDecl(self, node): if __name__ == "__main__": - if len(sys.argv) != 2: - sys.exit(1) + genfname = sys.argv[1] if len(sys.argv) >= 2 else 'gen.c' - ast = parse_file(sys.argv[1], use_cpp=True, cpp_args=[r'-Ifake', r'-I.']) + # generate simple C file including all relevant headers. + with open(genfname, 'w') as fh: + fh.write('#define __attribute__(x) \n') + for subdir, dirs, files in os.walk('include/capi'): + for incf in [f for f in files if f[-2:] == '.h']: + fh.write('#include "' + os.path.join(subdir, incf) + '"\n') + fh.write('\nint main(int argc, char** argv)\n{\n\treturn 0;\n}') + + ast = parse_file(genfname, use_cpp=True, cpp_args=[r'-Ifake', r'-I.']) # ast.show() StructVisitor().visit(ast)