|
1 # bdiff.py - CFFI implementation of bdiff.c |
|
2 # |
|
3 # Copyright 2016 Maciej Fijalkowski <fijall@gmail.com> |
|
4 # |
|
5 # This software may be used and distributed according to the terms of the |
|
6 # GNU General Public License version 2 or any later version. |
|
7 |
1 from __future__ import absolute_import |
8 from __future__ import absolute_import |
2 |
9 |
3 import cffi |
10 import struct |
4 import os |
|
5 |
11 |
6 ffi = cffi.FFI() |
12 from ..pure.bdiff import * |
7 ffi.set_source("_bdiff_cffi", |
13 from . import _bdiff |
8 open(os.path.join(os.path.join(os.path.dirname(__file__), '..'), |
|
9 'bdiff.c')).read(), include_dirs=['mercurial']) |
|
10 ffi.cdef(""" |
|
11 struct bdiff_line { |
|
12 int hash, n, e; |
|
13 ssize_t len; |
|
14 const char *l; |
|
15 }; |
|
16 |
14 |
17 struct bdiff_hunk; |
15 ffi = _bdiff.ffi |
18 struct bdiff_hunk { |
16 lib = _bdiff.lib |
19 int a1, a2, b1, b2; |
|
20 struct bdiff_hunk *next; |
|
21 }; |
|
22 |
17 |
23 int bdiff_splitlines(const char *a, ssize_t len, struct bdiff_line **lr); |
18 def blocks(sa, sb): |
24 int bdiff_diff(struct bdiff_line *a, int an, struct bdiff_line *b, int bn, |
19 a = ffi.new("struct bdiff_line**") |
25 struct bdiff_hunk *base); |
20 b = ffi.new("struct bdiff_line**") |
26 void bdiff_freehunks(struct bdiff_hunk *l); |
21 ac = ffi.new("char[]", str(sa)) |
27 void free(void*); |
22 bc = ffi.new("char[]", str(sb)) |
28 """) |
23 l = ffi.new("struct bdiff_hunk*") |
|
24 try: |
|
25 an = lib.bdiff_splitlines(ac, len(sa), a) |
|
26 bn = lib.bdiff_splitlines(bc, len(sb), b) |
|
27 if not a[0] or not b[0]: |
|
28 raise MemoryError |
|
29 count = lib.bdiff_diff(a[0], an, b[0], bn, l) |
|
30 if count < 0: |
|
31 raise MemoryError |
|
32 rl = [None] * count |
|
33 h = l.next |
|
34 i = 0 |
|
35 while h: |
|
36 rl[i] = (h.a1, h.a2, h.b1, h.b2) |
|
37 h = h.next |
|
38 i += 1 |
|
39 finally: |
|
40 lib.free(a[0]) |
|
41 lib.free(b[0]) |
|
42 lib.bdiff_freehunks(l.next) |
|
43 return rl |
29 |
44 |
30 if __name__ == '__main__': |
45 def bdiff(sa, sb): |
31 ffi.compile() |
46 a = ffi.new("struct bdiff_line**") |
|
47 b = ffi.new("struct bdiff_line**") |
|
48 ac = ffi.new("char[]", str(sa)) |
|
49 bc = ffi.new("char[]", str(sb)) |
|
50 l = ffi.new("struct bdiff_hunk*") |
|
51 try: |
|
52 an = lib.bdiff_splitlines(ac, len(sa), a) |
|
53 bn = lib.bdiff_splitlines(bc, len(sb), b) |
|
54 if not a[0] or not b[0]: |
|
55 raise MemoryError |
|
56 count = lib.bdiff_diff(a[0], an, b[0], bn, l) |
|
57 if count < 0: |
|
58 raise MemoryError |
|
59 rl = [] |
|
60 h = l.next |
|
61 la = lb = 0 |
|
62 while h: |
|
63 if h.a1 != la or h.b1 != lb: |
|
64 lgt = (b[0] + h.b1).l - (b[0] + lb).l |
|
65 rl.append(struct.pack(">lll", (a[0] + la).l - a[0].l, |
|
66 (a[0] + h.a1).l - a[0].l, lgt)) |
|
67 rl.append(str(ffi.buffer((b[0] + lb).l, lgt))) |
|
68 la = h.a2 |
|
69 lb = h.b2 |
|
70 h = h.next |
|
71 |
|
72 finally: |
|
73 lib.free(a[0]) |
|
74 lib.free(b[0]) |
|
75 lib.bdiff_freehunks(l.next) |
|
76 return "".join(rl) |