#! /usr/bin/env python # -*- coding: UTF-8 -*- # # $Id$ # # SWIG based PHP binding for Lasso Library # # 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 """Correct SWIG output for PHP binding. The PHP binding of SWIG version 1.3.22 has several bugs: (1) It wraps NULL pointers into non NULL PHP objects. (2) It doesn't handle dynamic cast of function results well: After the C object is dynamically casted, it creates a statically casted PHP object. (3) It handles badly optional arguments of methods. This program corrects (1) and (2), by replacing things like: if (!result) { ZVAL_NULL(return_value); } else { swig_type_info *ty = SWIG_TypeDynamicCast(SWIGTYPE_p_LassoXXX, (void **) &result); SWIG_SetPointerZval(return_value, (void *)result, ty, 1); } /* Wrap this return value */ if (this_ptr) { /* NATIVE Constructor, use this_ptr */ zval *_cPtr; MAKE_STD_ZVAL(_cPtr); *_cPtr = *return_value; INIT_ZVAL(*return_value); add_property_zval(this_ptr,"_cPtr",_cPtr); } else if (! this_ptr) { /* ALTERNATIVE Constructor, make an object wrapper */ zval *obj, *_cPtr; MAKE_STD_ZVAL(obj); MAKE_STD_ZVAL(_cPtr); *_cPtr = *return_value; INIT_ZVAL(*return_value); object_init_ex(obj,ptr_ce_swig_LassoXXX); add_property_zval(obj,"_cPtr",_cPtr); *return_value=*obj; } with: if (!result) { ZVAL_NULL(return_value); } else { swig_type_info *ty = SWIG_TypeDynamicCast(SWIGTYPE_p_LassoXXX, (void **) &result); SWIG_SetPointerZval(return_value, (void *)result, ty, 1); /* Wrap this return value */ if (this_ptr) { /* NATIVE Constructor, use this_ptr */ zval *_cPtr; MAKE_STD_ZVAL(_cPtr); *_cPtr = *return_value; INIT_ZVAL(*return_value); add_property_zval(this_ptr,"_cPtr",_cPtr); } else if (! this_ptr) { /* ALTERNATIVE Constructor, make an object wrapper */ zval *obj, *_cPtr; MAKE_STD_ZVAL(obj); MAKE_STD_ZVAL(_cPtr); *_cPtr = *return_value; INIT_ZVAL(*return_value); object_init_ex(obj,get_node_info_with_swig(ty)->php); add_property_zval(obj,"_cPtr",_cPtr); *return_value=*obj; }} and if (!result) { ZVAL_NULL(return_value); } else { swig_type_info *ty = SWIG_TypeDynamicCast(SWIGTYPE_p_LassoXXX, (void **) &result); SWIG_SetPointerZval(return_value, (void *)result, ty, 0); } /* Wrap this return value */ { /* ALTERNATIVE Constructor, make an object wrapper */ zval *obj, *_cPtr; MAKE_STD_ZVAL(obj); MAKE_STD_ZVAL(_cPtr); *_cPtr = *return_value; INIT_ZVAL(*return_value); object_init_ex(obj,ptr_ce_swig_LassoXXX); add_property_zval(obj,"_cPtr",_cPtr); *return_value=*obj; } with: if (!result) { ZVAL_NULL(return_value); } else { swig_type_info *ty = SWIG_TypeDynamicCast(SWIGTYPE_p_LassoXXX, (void **) &result); SWIG_SetPointerZval(return_value, (void *)result, ty, 0); /* Wrap this return value */ { /* ALTERNATIVE Constructor, make an object wrapper */ zval *obj, *_cPtr; MAKE_STD_ZVAL(obj); MAKE_STD_ZVAL(_cPtr); *_cPtr = *return_value; INIT_ZVAL(*return_value); object_init_ex(obj,get_node_info_with_swig(ty)->php); add_property_zval(obj,"_cPtr",_cPtr); *return_value=*obj; }} In old SWIG versions, this program corrects (3), by replacing things like: if(zend_get_parameters_array_ex(arg_count-argbase,args)!=SUCCESS) with: if(zend_get_parameters_array_ex(arg_count,args)!=SUCCESS) and by replacing: if(arg_count > 1) { with: if(arg_count > 1 - argbase) { In newer SWIG versions, this program corrects (3), by replacing code like: if(arg_count<2 || arg_count>4) with: if(arg_count<1 || arg_count>3) whenever the function uses a this_ptr. """ import re import sys wrap = sys.stdin.read() swig_version = sys.argv[1] major, minor, release = re.match('(.*)\.(.*)\.(.*)', swig_version).groups() major = int(major) minor = int(minor) release = int(release) if major < 1 or (major == 1 and (minor < 3 or (minor == 3 and release < 32))): # (1) begin = """ } /* Wrap this return value */ """ end = """ *return_value=*obj; } """ i = wrap.find(begin) while i >= 0: j = wrap.find(end, i) + len(end) segment = wrap[i:j] segment = segment.replace(begin, """ /* Wrap this return value */ """) segment = segment.replace(end, """ *return_value=*obj; }} """) wrap = '%s%s%s' % (wrap[:i], segment, wrap[j:]) i = wrap.find(begin, i + len(segment)) # (2) begin = 'swig_type_info *ty = SWIG_TypeDynamicCast(' end = """ *return_value=*obj; }} """ i = wrap.find(begin) while i >= 0: j = wrap.find(end, i) + len(end) #print >> sys.stderr, "END:", j, len(end) if j < len(end): # bails out if not found break segment = wrap[i:j] x = segment.find('object_init_ex(obj,') + len('object_init_ex(obj,') y = segment.find(')', x) segment = '%s%s%s' % (segment[:x], 'get_node_info_with_swig(ty)->php', segment[y:]) wrap = '%s%s%s' % (wrap[:i], segment, wrap[j:]) i = wrap.find(begin, i + len(segment)) # (3) wrap = wrap.replace('if(zend_get_parameters_array_ex(arg_count-argbase,args)!=SUCCESS)', 'if(zend_get_parameters_array_ex(arg_count,args)!=SUCCESS)') function_pattern = re.compile('ZEND_NAMED_FUNCTION(.*?)\n}', re.DOTALL) argcount_less_pattern = re.compile('if\(arg_count<(\d) \|\| arg_count>(\d)') argcount_more_pattern = re.compile('if\(arg_count > (\d)\)') def rep2(match): arg1 = int(match.group(1)) - 1 arg2 = int(match.group(2)) - 1 return 'if(arg_count<%s || arg_count>%s' % (arg1, arg2) def rep3(match): arg1 = int(match.group(1)) - 1 return 'if(arg_count > %s)' % arg1 def rep(match): m = match.group(0) if not 'This function uses a this_ptr' in m: return m if not 'arg_count<' in m: return m lines = match.group(0).splitlines() s = [] for l in lines: if l.startswith('if(arg_count<'): l = argcount_less_pattern.sub(rep2, l) elif l.startswith(' if(arg_count >'): l = argcount_more_pattern.sub(rep3, l) s.append(l) return ''.join(s) wrap = function_pattern.sub(rep, wrap) wrap = re.sub(r'zend_register_internal_class_ex(.*)NULL,NULL\)', r'zend_register_internal_class_ex\1NULL,NULL TSRMLS_CC)', wrap) wrap = re.sub('zend_rsrc_list_get_rsrc_type(.*)lval *\)', r'zend_rsrc_list_get_rsrc_type\1lval TSRMLS_CC)', wrap) else: # Bis for swig 1.3.33 # (1) begin = """ } { /* Wrap this return value */ """ end = """ } """ i = wrap.find(begin) while i >= 0: j = wrap.find(end, i+len(begin)) + len(end) segment = wrap[i:j] segment = segment.replace(begin, """ /* Wrap this return value */ """) segment = segment.replace(end, """ } """) wrap = '%s%s%s' % (wrap[:i], segment, wrap[j:]) i = wrap.find(begin, i + len(segment)) # (2) begin = 'swig_type_info *ty = SWIG_TypeDynamicCast(' end = """ } """ i = wrap.find(begin) while i >= 0: j = wrap.find(end, i+len(begin)) + len(end) if j < len(end): # bails out if not found i = wrap.find(begin, i + len(segment)) break segment = wrap[i:j] if not 'object_init_ex' in segment: i = wrap.find(begin, i + len(segment)) continue x = segment.find('object_init_ex(return_value,') + len('object_init_ex(return_value,') y = segment.find(')', x) segment = '%s%s%s' % (segment[:x], 'get_node_info_with_swig(ty)->php', segment[y:]) wrap = '%s%s%s' % (wrap[:i], segment, wrap[j:]) i = wrap.find(begin, i + len(segment)) print wrap