blob: 254b0057240997fbcb483af2e410d57568441f13 [file] [log] [blame]
#
# gen_swig.py -- generate SWIG interface files
#
import gen_base
import gen_make
import os, re, string
from gen_base import unique, native_path
class Generator(gen_make.Generator):
"""Generate SWIG interface files"""
# Ignore svn_md5.h because SWIG can't parse it
_ignores = ["svn_md5.h"];
def __init__(self, fname, verfname, options=None):
gen_base.GeneratorBase.__init__(self, fname, verfname, options)
def _proxy_filename(self, include_filename):
"""Convert a .h filename into a _h.swg filename"""
return string.replace(include_filename,".h","_h.swg")
def _write_nodefault_calls(self, structs):
"""Write proxy definitions to a SWIG interface file"""
self.ofile.write("\n/* No default constructors for opaque structs */\n")
self.ofile.write('#ifdef SWIGPYTHON\n');
for structName, structDefinition in structs:
if not structDefinition:
self.ofile.write('%%nodefault %s;\n' % structName)
self.ofile.write('#endif\n');
def _write_includes(self, includes, base_fname):
"""Write includes to a SWIG interface file"""
self.ofile.write('\n/* Includes */\n')
# Include dependencies
self.ofile.write('#ifdef SWIGPYTHON\n');
apr_included = None
self.ofile.write('%import proxy.swg\n')
for include in includes:
if include in self._include_basenames:
self.ofile.write('%%include %s\n' % self._proxy_filename(include))
elif include[:3] == "apr" and not apr_included:
apr_included = 1
self.ofile.write('%import apr.swg\n')
self.ofile.write('#endif\n');
# Include the headerfile itself
self.ofile.write('%%{\n#include "%s"\n%%}\n' % base_fname)
if base_fname not in self._ignores:
self.ofile.write('%%include %s\n' % base_fname)
def _write_proxy_definitions(self, structs):
"""Write proxy definitions to a SWIG interface file"""
self.ofile.write('\n/* Structure definitions */\n')
self.ofile.write('#ifdef SWIGPYTHON\n');
for structName, structDefinition in structs:
if structDefinition:
self.ofile.write('%%proxy(%s);\n' % structName)
else:
self.ofile.write('%%opaque_proxy(%s);\n' % structName)
self.ofile.write('#endif\n');
"""Regular expression for parsing includes from a C header file"""
_re_includes = re.compile(r'#\s*include\s*[<"]([^<">;\s]+)')
"""Regular expression for parsing structs from a C header file"""
_re_structs = re.compile(r'\btypedef\s+struct\s+(svn_[a-z_0-9]+_t)\b\s*(\{?)')
def _write_swig_interface_file(self, base_fname, includes, structs):
"""Convert a header file into a SWIG header file"""
# Calculate output filename from base filename
output_fname = os.path.join(self.swig_proxy_dir,
self._proxy_filename(base_fname))
# Open the output file
self.ofile = open(output_fname, 'w')
self.ofile.write('/* Proxy classes for %s\n' % base_fname)
self.ofile.write(' * DO NOT EDIT -- AUTOMATICALLY GENERATED */\n')
# Write list of structs for which we shouldn't define constructors
# by default
self._write_nodefault_calls(structs)
# Write includes into the SWIG interface file
self._write_includes(includes, base_fname)
# Write proxy definitions into the SWIG interface file
self._write_proxy_definitions(structs)
# Close our output file
self.ofile.close()
def _process_header_file(self, fname):
# Read the contents of the header file
contents = open(fname).read()
# Write includes into the SWIG interface file
includes = unique(self._re_includes.findall(contents))
# Get list of structs
structs = unique(self._re_structs.findall(contents))
# Get the location of the output file
base_fname = os.path.basename(fname)
self._write_swig_interface_file(base_fname, includes, structs)
def write(self):
"""Generate SWIG interface files"""
header_files = map(native_path, self.includes)
self._include_basenames = map(os.path.basename, header_files)
for fname in header_files:
if fname[-2:] == ".h":
self._process_header_file(fname)