lasso/bindings/php4/lang.py

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