diff --git a/mercurial/pure/bdiff.py b/mercurial/pure/bdiff.py --- a/mercurial/pure/bdiff.py +++ b/mercurial/pure/bdiff.py @@ -12,6 +12,10 @@ import difflib import re import struct +from . import policy +policynocffi = policy.policynocffi +modulepolicy = policy.policy + def splitnewlines(text): '''like str.splitlines, but only split on newlines.''' lines = [l + '\n' for l in text.split('\n')] @@ -96,3 +100,37 @@ def fixws(text, allws): text = re.sub('[ \t\r]+', ' ', text) text = text.replace(' \n', '\n') return text + +if modulepolicy not in policynocffi: + try: + from _bdiff_cffi import ffi, lib + except ImportError: + if modulepolicy == 'cffi': # strict cffi import + raise + else: + def blocks(sa, sb): + a = ffi.new("struct bdiff_line**") + b = ffi.new("struct bdiff_line**") + ac = ffi.new("char[]", sa) + bc = ffi.new("char[]", sb) + try: + an = lib.bdiff_splitlines(ac, len(sa), a) + bn = lib.bdiff_splitlines(bc, len(sb), b) + if not a[0] or not b[0]: + raise MemoryError + l = ffi.new("struct bdiff_hunk*") + count = lib.bdiff_diff(a[0], an, b[0], bn, l) + if count < 0: + raise MemoryError + rl = [None] * count + h = l.next + i = 0 + while h: + rl[i] = (h.a1, h.a2, h.b1, h.b2) + h = h.next + i += 1 + finally: + lib.free(a[0]) + lib.free(b[0]) + lib.bdiff_freehunks(l.next) + return rl diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -319,7 +319,9 @@ class hgbuildpy(build_py): self.distribution.ext_modules = [] elif self.distribution.cffi: import setup_mpatch_cffi - exts = [setup_mpatch_cffi.ffi.distutils_extension()] + import setup_bdiff_cffi + exts = [setup_mpatch_cffi.ffi.distutils_extension(), + setup_bdiff_cffi.ffi.distutils_extension()] # cffi modules go here if sys.platform == 'darwin': import setup_osutil_cffi diff --git a/setup_bdiff_cffi.py b/setup_bdiff_cffi.py new file mode 100644 --- /dev/null +++ b/setup_bdiff_cffi.py @@ -0,0 +1,31 @@ +from __future__ import absolute_import + +import cffi +import os + +ffi = cffi.FFI() +ffi.set_source("_bdiff_cffi", + open(os.path.join(os.path.join(os.path.dirname(__file__), 'mercurial'), + 'bdiff.c')).read(), include_dirs=['mercurial']) +ffi.cdef(""" +struct bdiff_line { + int hash, n, e; + ssize_t len; + const char *l; +}; + +struct bdiff_hunk; +struct bdiff_hunk { + int a1, a2, b1, b2; + struct bdiff_hunk *next; +}; + +int bdiff_splitlines(const char *a, ssize_t len, struct bdiff_line **lr); +int bdiff_diff(struct bdiff_line *a, int an, struct bdiff_line *b, int bn, + struct bdiff_hunk *base); +void bdiff_freehunks(struct bdiff_hunk *l); +void free(void*); +""") + +if __name__ == '__main__': + ffi.compile()