|
1 # mpatch.py - CFFI implementation of mpatch.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 from ..pure.mpatch import * |
4 import os |
11 from ..pure.mpatch import mpatchError # silence pyflakes |
|
12 from . import _mpatch |
5 |
13 |
6 ffi = cffi.FFI() |
14 ffi = _mpatch.ffi |
7 mpatch_c = os.path.join(os.path.join(os.path.dirname(__file__), '..', |
15 lib = _mpatch.lib |
8 'mpatch.c')) |
|
9 ffi.set_source("_mpatch_cffi", open(mpatch_c).read(), |
|
10 include_dirs=["mercurial"]) |
|
11 ffi.cdef(""" |
|
12 |
16 |
13 struct mpatch_frag { |
17 @ffi.def_extern() |
14 int start, end, len; |
18 def cffi_get_next_item(arg, pos): |
15 const char *data; |
19 all, bins = ffi.from_handle(arg) |
16 }; |
20 container = ffi.new("struct mpatch_flist*[1]") |
|
21 to_pass = ffi.new("char[]", str(bins[pos])) |
|
22 all.append(to_pass) |
|
23 r = lib.mpatch_decode(to_pass, len(to_pass) - 1, container) |
|
24 if r < 0: |
|
25 return ffi.NULL |
|
26 return container[0] |
17 |
27 |
18 struct mpatch_flist { |
28 def patches(text, bins): |
19 struct mpatch_frag *base, *head, *tail; |
29 lgt = len(bins) |
20 }; |
30 all = [] |
21 |
31 if not lgt: |
22 extern "Python" struct mpatch_flist* cffi_get_next_item(void*, ssize_t); |
32 return text |
23 |
33 arg = (all, bins) |
24 int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist** res); |
34 patch = lib.mpatch_fold(ffi.new_handle(arg), |
25 ssize_t mpatch_calcsize(size_t len, struct mpatch_flist *l); |
35 lib.cffi_get_next_item, 0, lgt) |
26 void mpatch_lfree(struct mpatch_flist *a); |
36 if not patch: |
27 static int mpatch_apply(char *buf, const char *orig, size_t len, |
37 raise mpatchError("cannot decode chunk") |
28 struct mpatch_flist *l); |
38 outlen = lib.mpatch_calcsize(len(text), patch) |
29 struct mpatch_flist *mpatch_fold(void *bins, |
39 if outlen < 0: |
30 struct mpatch_flist* (*get_next_item)(void*, ssize_t), |
40 lib.mpatch_lfree(patch) |
31 ssize_t start, ssize_t end); |
41 raise mpatchError("inconsistency detected") |
32 """) |
42 buf = ffi.new("char[]", outlen) |
33 |
43 if lib.mpatch_apply(buf, text, len(text), patch) < 0: |
34 if __name__ == '__main__': |
44 lib.mpatch_lfree(patch) |
35 ffi.compile() |
45 raise mpatchError("error applying patches") |
|
46 res = ffi.buffer(buf, outlen)[:] |
|
47 lib.mpatch_lfree(patch) |
|
48 return res |