517 lines
18 KiB
Python
517 lines
18 KiB
Python
# Lasso - A free implementation of the Liberty Alliance specifications.
|
|
#
|
|
# Copyright (C) 2004-2007 Entr'ouvert
|
|
# http://lasso.entrouvert.org
|
|
#
|
|
# Authors: See AUTHORS file in top-level directory.
|
|
#
|
|
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
import sys
|
|
import os
|
|
import utils
|
|
|
|
module_file = '_lasso.c'
|
|
header_file = '_lasso.h'
|
|
php_file = 'lasso.php'
|
|
|
|
def zval(name):
|
|
return 'zval_' + name
|
|
|
|
class Binding:
|
|
def __init__(self, binding_data):
|
|
self.binding_data = binding_data
|
|
self.module_fd = open(module_file, 'w')
|
|
self.header_fd = open(header_file, 'w')
|
|
self.php_fd = open(php_file, 'w')
|
|
self.functions_list = list()
|
|
self.shiftcount = 0
|
|
|
|
def __del__(self):
|
|
close(self.module_fd)
|
|
close(self.header_fd)
|
|
close(self.php_fd)
|
|
|
|
# Helper code
|
|
def is_object(self, t):
|
|
return t not in ['char*', 'const char*', 'gchar*', 'const gchar*', 'GList*', 'GHashTable*',
|
|
'xmlNode*', 'int', 'gint', 'gboolean', 'const gboolean'] + self.binding_data.enums
|
|
|
|
def error(self,str):
|
|
print >> sys.stderr, 'E: %s' % str
|
|
|
|
def warning(self,str):
|
|
print >> sys.stderr, 'W: %s' % str
|
|
|
|
def printshift(self,fd):
|
|
if self.shiftcount:
|
|
print >> fd, (self.shiftcount-1)*' ',
|
|
|
|
def shift(self):
|
|
self.shiftcount += 4
|
|
|
|
def unshift(self):
|
|
self.shiftcount -= 4
|
|
|
|
def module(self,str):
|
|
self.printshift(self.module_fd)
|
|
print >> self.module_fd, str
|
|
|
|
def php(self,str):
|
|
self.printshift(self.php_fd)
|
|
print >> self.php_fd, str
|
|
|
|
def header(self,str):
|
|
self.printshift(self.header_fd)
|
|
print >> self.header_fd, str
|
|
|
|
def define(self,name,value):
|
|
self.header('#define %s %s' % (name,value))
|
|
|
|
def include(self, str):
|
|
self.module('#include "%s"' % str)
|
|
|
|
def function(self, function_name):
|
|
self.functions_list.append(function_name)
|
|
self.module('PHP_FUNCTION(%s)' % function_name)
|
|
|
|
def open(self):
|
|
self.module('{')
|
|
self.shift()
|
|
|
|
def close(self):
|
|
self.unshift()
|
|
self.module('}')
|
|
|
|
def ret(self, value):
|
|
self.module('return %s;' % value)
|
|
|
|
def success(self):
|
|
self.ret('SUCCESS')
|
|
|
|
def declare_zval(self, name):
|
|
self.declare('zval*', zval(name))
|
|
|
|
def declare(self, type, name):
|
|
self.module('%s %s;' % (type, name))
|
|
|
|
def comment(self, str):
|
|
self.module('/* %s */' % str)
|
|
|
|
def free(self,name):
|
|
self.module('free(%s);' % name)
|
|
|
|
def get_php_list(self, name, element_type):
|
|
self.comment(' Get php list %s of type %s from %s ' % (name, element_type, zval(name)))
|
|
|
|
|
|
def get_php_hashtable(self, name, element_type):
|
|
self.comment(' Get php hashtable %s of type %s from %s ' % (name, element_type, zval(name)))
|
|
|
|
def get_object(self, name, type):
|
|
self.comment(' Get object %s of type %s from php resource %s ' % (name, type, zval(name)))
|
|
|
|
def parse_format_arg(self, arg):
|
|
type, name, options = arg
|
|
ret = ''
|
|
if type == 'gboolean':
|
|
ret = 'b'
|
|
return ret
|
|
elif type in ['int', 'gint'] + self.binding_data.enums:
|
|
ret = 'l'
|
|
return ret
|
|
elif type in ('char*', 'gchar*','const char*','const gchar*'):
|
|
ret = 's'
|
|
elif type == 'xmlNode*':
|
|
ret = 's'
|
|
elif type == 'GList*':
|
|
ret = 'a'
|
|
elif type == 'GHashTable*':
|
|
ret = 'a'
|
|
elif self.is_object(type):
|
|
ret = 'r'
|
|
else:
|
|
self.error('%s of type %s has no format string' % (name, type))
|
|
if options.get('nonull') == None and ret:
|
|
ret += '!'
|
|
return ret
|
|
|
|
def generate_parse_args(self, arg):
|
|
type, name, options = arg
|
|
ret = ''
|
|
if type == 'gboolean' or type in ['int', 'gint'] + self.binding_data.enums:
|
|
self.declare(type, name)
|
|
return list(name)
|
|
elif type in ('char*', 'gchar*','const char*','const gchar*'):
|
|
self.declare('char*', name)
|
|
self.declare('int', name + '_len')
|
|
return (name, name + '_len')
|
|
elif type == 'xmlNode*':
|
|
self.declare('char*', name + '_str')
|
|
self.declare('int', name + '_len')
|
|
self.declare('xmlNode*', name)
|
|
return (name + '_str', name + '_len')
|
|
elif type == 'GList*' or type == 'GHashTable*' or self.is_object(type):
|
|
self.declare_zval(name)
|
|
self.declare(type, name)
|
|
return list(zval(name))
|
|
else:
|
|
self.error('%s of type %s has no format arg' % (name, type))
|
|
return list()
|
|
|
|
def method_prologue(self, klass, name, args = list()):
|
|
self.function(name)
|
|
self.open()
|
|
self.declare('int', 'zpp_ret')
|
|
self.declare(klass.name + '*', 'a_gobject')
|
|
this = zval('this')
|
|
self.declare_zval('this')
|
|
# this should not be null
|
|
parse_format = 'r'
|
|
parse_args = list(this)
|
|
for arg in args:
|
|
type, name, options = arg
|
|
# Create parse_format
|
|
parse_format += self.parse_format_char(arg)
|
|
# Allocate variables
|
|
parse_args = self.generate_parse_args(arg)
|
|
# Call parse parameters
|
|
self.module('zpp_ret = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "%s", %s)' % (parse_format, ','.join([ "&" + x for x in parse_args])))
|
|
self.module('if (zpp_ret == Failure)')
|
|
self.open()
|
|
self.module('RETURN_NULL();');
|
|
self.close()
|
|
# Convert the resource
|
|
self.module('ZEND_FETCH_RESOURCE(a_gobject, %s*, &%s, -1, PHP_LASSO_GOBJECT_RES_NAME, le_lasso_gobject);')
|
|
self.module('if (a_gobject == NULL)')
|
|
self.open()
|
|
self.module('zend_error(E_WARNING, "Calling a method on a null GObject resource, big problem");')
|
|
self.module('RETURN_NULL();');
|
|
self.close()
|
|
for arg in args:
|
|
type, name, options = arg
|
|
if type == 'gboolean' and type in ['int', 'gint'] + self.binding_data.enums and type in ('char*', 'gchar*','const char*','const gchar*'):
|
|
pass
|
|
elif type == 'xmlNode*':
|
|
self.module('get_xml_node_from_string(&%(name)s,%(name)s_str);' % { 'name': name })
|
|
elif type == 'GList*':
|
|
self.get_php_list(name, options.get('element_type'))
|
|
elif type == 'GHashTable*':
|
|
self.get_php_hashtable(name, options.get('element_type'))
|
|
elif self.is_object(type):
|
|
self.get_object(name, type)
|
|
|
|
def method_epilogue(self, args = list()):
|
|
for arg in args:
|
|
type, name, options = arg
|
|
type, name, options = arg
|
|
if type == 'gboolean' and type in ['int', 'gint'] + self.binding_data.enums and type in ('char*', 'gchar*','const char*','const gchar*'):
|
|
pass
|
|
elif type == 'xmlNode*':
|
|
self.free_xmldoc(name)
|
|
elif type == 'GList*':
|
|
self.free_glist(name, options.get('element_type'))
|
|
elif type == 'GHashTable*':
|
|
self.free_hashtable(name, options.get('element_type'))
|
|
elif self.is_object(type):
|
|
pass
|
|
else:
|
|
self.error('Bizarre type %s' % type)
|
|
self.close()
|
|
|
|
def generate_module_dummy_function(self, name):
|
|
self.module(name)
|
|
self.open()
|
|
self.success()
|
|
self.close()
|
|
# Type helpers
|
|
def update_c_value(self, left, right, type, options, free = True, copy = False):
|
|
if type == 'gboolean' and type in ['int', 'gint'] + self.binding_data.enums:
|
|
self.module('%s = %s;' % (left, right))
|
|
return
|
|
|
|
if free:
|
|
self.module('if (%s)' % left)
|
|
self.open()
|
|
self.free(left, type, options)
|
|
self.close()
|
|
pat = ''
|
|
if type in ('char*','gchar*') and copy:
|
|
pat = '%s = g_strdup(%s);'
|
|
else:
|
|
par = '%s = %s;'
|
|
self.module(pat % (left, right))
|
|
|
|
def return_c_value(self, type, name, options = dict()):
|
|
if type is None:
|
|
return
|
|
|
|
if type == 'gboolean':
|
|
self.module('RETVAL_BOOL(%s);' % name)
|
|
return
|
|
elif type in ['int', 'gint'] + self.binding_data.enums:
|
|
self.module('RETVAL_LONG(%s);' % name)
|
|
return
|
|
# Pointer types
|
|
self.module('if (%s)' % name)
|
|
self.open()
|
|
if type in ('char*', 'gchar*','const char*','const gchar*'):
|
|
if options.get('eallocated') == 1:
|
|
self.module('RETVAL_STRING(%s,0);' % name)
|
|
else:
|
|
self.module('RETVAL_STRING(%s,1);' % name)
|
|
elif type == 'xmlNode*':
|
|
self.open()
|
|
self.declare('char*','xmlString')
|
|
self.module('xmlString = get_string_from_xml_node(%s);' % name)
|
|
self.return_c_value('char*','xmlString', { 'eallocated': 1 })
|
|
self.close()
|
|
elif type == 'GList*':
|
|
pass
|
|
elif type == 'GHashTable*':
|
|
pass
|
|
elif self.is_object(type):
|
|
self.module('ZVAL_REGISTER_RESOURCE(return_value, %s, le_lasso_gobject);' % name)
|
|
else:
|
|
self.error('%s of type %s is not returnable' % (name, type))
|
|
self.close()
|
|
self.module('else')
|
|
self.open()
|
|
self.module('RETVAL_NULL();')
|
|
self.close()
|
|
#
|
|
|
|
def generate(self):
|
|
self.generate_php()
|
|
self.generate_module()
|
|
# Must be called last because generate_module
|
|
# compute self.functions_lists
|
|
# that is needed by generate_header_functions_list
|
|
self.generate_header()
|
|
|
|
# Generation of the C header
|
|
# Generate the lasso.h file
|
|
def generate_header(self):
|
|
self.header('/* this file has been generated automatically; do not edit */')
|
|
self.header('#ifndef PHP_LASSO_H')
|
|
self.header('#define PHP_LASSO_H 1')
|
|
self.header('')
|
|
self.define('PHP_LASSO_EXTNAME', '"lasso"')
|
|
self.define('PHP_LASSO_VERSION', '"2.1.1"')
|
|
self.define('PHP_LASSO_GOBJECT_RES_NAME', 'LassoGObject')
|
|
self.header('PHP_MINIT_FUNCTION(lasso);')
|
|
self.header('PHP_MSHUTDOWN_FUNCTION(lasso);')
|
|
self.header('PHP_RINIT_FUNCTION(lasso);')
|
|
self.generate_header_functions_list()
|
|
self.generate_header_globals()
|
|
# Declare GObject resource destructor
|
|
self.header('static void php_lasso_gobject_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);')
|
|
self.header('extern zend_module_entry lasso_module_entry;')
|
|
self.define('phpext_lasso_ptr','&lasso_module_entry')
|
|
self.header('#endif')
|
|
|
|
def generate_header_functions_list(self):
|
|
for m in self.functions_list:
|
|
self.header('PHP_FUNCTION(%s);' % m)
|
|
self.header('')
|
|
|
|
def generate_header_globals(self):
|
|
self.header('#ifdef ZTS')
|
|
self.header('#include "TSRM.h"')
|
|
self.header('#endif')
|
|
self.header('')
|
|
self.header('ZEND_BEGIN_MODULE_GLOBALS(lasso)')
|
|
self.header('ZEND_END_MODULE_GLOBALS(lasso)')
|
|
self.header('')
|
|
self.header('#ifdef ZTS')
|
|
self.header('#define LASSO_G(v) TSRMG(lasso_globals_id, zend_lasso_globals *, v)')
|
|
self.header('#else')
|
|
self.header('#define LASSO_G(v) (lasso_globals.v)')
|
|
self.header('#endif')
|
|
|
|
# Generation of the C module
|
|
def generate_module(self):
|
|
self.generate_module_top()
|
|
self.generate_module_minit()
|
|
self.generate_module_gobject_resource_dtor()
|
|
self.generate_functions()
|
|
self.generate_getters_setters()
|
|
self.generate_function_declarations()
|
|
self.generate_module_entry()
|
|
self.generate_module_php_ini()
|
|
|
|
def generate_module_top(self):
|
|
self.include('php.h')
|
|
self.include('php_ini.h')
|
|
self.include(header_file)
|
|
self.include('lasso_php4_helper.c')
|
|
self.module('ZEND_DECLARE_MODULE_GLOBALS(lasso)')
|
|
self.module('')
|
|
self.module('#if COMPILE_DL_LASSO')
|
|
self.module('ZEND_GET_MODULE(lasso) ')
|
|
self.module('#endif')
|
|
self.module('/* GObject resource type */')
|
|
self.module('int le_lasso_gobject');
|
|
|
|
def generate_module_entry(self):
|
|
self.module('zend_module_entry lasso_module_entry = {')
|
|
self.module('#if ZEND_MODULE_API_NO >= 20010901')
|
|
self.module(' STANDARD_MODULE_HEADER,')
|
|
self.module('#endif')
|
|
self.module(' PHP_HELLO_WORLD_EXTNAME,')
|
|
self.module(' lasso_functions,')
|
|
self.module(' PHP_MINIT(lasso),')
|
|
self.module(' PHP_MSHUTDOWN(lasso),')
|
|
self.module(' PHP_RINIT(lasso), /* Request init function */')
|
|
self.module(' PHP_RSHUTDOWN(lasso) , /* Request shutdown function/ ')
|
|
self.module(' NULL, /* PHP info function */')
|
|
self.module('#if ZEND_MODULE_API_NO >= 20010901')
|
|
self.module(' PHP_HELLO_WORLD_VERSION,')
|
|
self.module('#endif')
|
|
self.module(' STANDARD_MODULE_PROPERTIES')
|
|
self.module('};')
|
|
|
|
def generate_module_gobject_resource_dtor(self):
|
|
self.module('static void php_lasso_gobject_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) {')
|
|
self.shift()
|
|
self.module('GObject *a_gobject;')
|
|
self.module('g_object_unref((GObject*)rsrc->ptr);')
|
|
self.unshift()
|
|
self.module('}')
|
|
|
|
def generate_module_php_ini(self):
|
|
self.module('PHP_INI_BEGIN()')
|
|
self.shift()
|
|
# self.module('PHP_INI_ENTRY("lasso.greeting", "Hello World", PHP_INI_ALL, NULL)')
|
|
# self.module('STD_PHP_INI_ENTRY("lasso.direction", "1", PHP_INI_ALL, OnUpdateBool, direction, zend_lasso_globals, lasso_globals)')
|
|
self.unshift()
|
|
self.module('PHP_INI_END()')
|
|
|
|
def generate_module_minit(self):
|
|
self.module('PHP_MINIT(lasso)')
|
|
self.open()
|
|
self.generate_module_minit_constants()
|
|
# Init globals
|
|
# self.module('LASSO_G(autocoin) = 1;')
|
|
self.generate_module_minit_register_resources()
|
|
self.success()
|
|
self.close()
|
|
|
|
def generate_module_minit_constants(self):
|
|
self.module('/* Constants (both enums and defines) */')
|
|
mapping = {
|
|
'i': 'REGISTER_LONG_CONSTANT("%(name)s", %(name)s, CONST_CS|CONST_PERSISTENT);',
|
|
's': 'REGISTER_STRING_CONSTANT("%(name)s", %(name)s, CONST_CS|CONST_PERSISTENT);',
|
|
'b': '''\
|
|
#ifdef %(name)s
|
|
REGISTER_LONG_CONSTANT("%(name)s", 1, CONST_CS|CONST_PERSISTENT);
|
|
#else
|
|
REGISTER_LONG_CONSTANT("%(name)s", 0, CONST_CS|CONST_PERSISTENT);
|
|
#endif''' }
|
|
for c in self.binding_data.constants:
|
|
constant_type, constant_name = c
|
|
if constant_type in mapping:
|
|
self.module(mapping[constant_type] % { 'name': constant_name } )
|
|
else:
|
|
self.error('unknown constant type "%s"' % constant_type)
|
|
|
|
|
|
def generate_module_minit_register_resources(self):
|
|
self.module('le_lasso_gobject = zend_register_list_destructors_ex(php_lasso_gobject_dtor, NULL, PHP_LASSO_GOBJECT_RES_NAME, module_number);')
|
|
|
|
|
|
def generate_module_mshutdown(self):
|
|
self.generate_module_dummy_function('PHP_MSHUTDOWN(lasso)')
|
|
|
|
def generate_module_rinit(self):
|
|
self.generate_module_dummy_function('PHP_RINIT(lasso)')
|
|
|
|
def generate_module_rshutdown(self):
|
|
self.generate_module_dummy_function('PHP_RSHUTDOWN(lasso)')
|
|
|
|
def generate_getters_setters(self):
|
|
for klass in self.binding_data.structs:
|
|
for member in klass.members:
|
|
self.generate_getter(klass, member)
|
|
self.generate_getter(klass, member)
|
|
|
|
def function_name(self, klass, member, suffix):
|
|
type, name, options = member
|
|
return '%s_%s_%s' % (klass.name, utils.format_as_camelcase(name), suffix)
|
|
def getter_function_name(self, klass, member):
|
|
return self.function_name(klass, member, 'get')
|
|
def setter_function_name(self, klass, member):
|
|
return self.function_name(klass, member, 'set')
|
|
def generate_getter(self, klass, member):
|
|
type, name, options = member
|
|
elem_type = options.get('elem_type')
|
|
function_name = self.getter_function_name(klass, member)
|
|
self.method_prologue(klass, function_name)
|
|
self.return_c_value(type, 'a_gobject->' + name, options)
|
|
self.method_epilogue()
|
|
|
|
def generate_setter(self, klass, member):
|
|
type, name, options = member
|
|
elem_type = options.get('elem_type')
|
|
function_name = self.setter_function_name(klass, member)
|
|
self.method_prologue(klass, function_name, list(member))
|
|
# Affectation: a_gobject->name = name
|
|
self.update_c_value('a_gobject->' + name, name, type, options, True, True)
|
|
self.method_epilogue()
|
|
|
|
def generate_functions(self):
|
|
pass
|
|
|
|
def generate_function(self):
|
|
pass
|
|
|
|
def generate_function_arg_decl(self):
|
|
pass
|
|
|
|
def generate_function_call(self):
|
|
pass
|
|
|
|
def generate_function_arg_free(self):
|
|
pass
|
|
|
|
def genreate_function_return(self):
|
|
pass
|
|
|
|
def generate_function_declarations(self):
|
|
pass
|
|
|
|
def generate_function_declaration(self):
|
|
pass
|
|
|
|
# Generate of the PHP file
|
|
def generate_php(self):
|
|
pass
|
|
|
|
def generate_php_objects(self):
|
|
pass
|
|
|
|
def generate_php_getters_setters(self):
|
|
pass
|
|
|
|
def generate_methods(self):
|
|
pass
|
|
|
|
def generate_exception_classes(self):
|
|
pass
|
|
|
|
def generate_exception_class(self):
|
|
pass
|
|
|