mpatch: remove dependency on Python.h in mpatch.c
Now all the CPython-related stuff are referenced only from
mpatch_module.c with mpatch.c being freely usable from
a future cffi module
--- a/mercurial/mpatch.c Mon Jul 18 19:02:30 2016 +0200
+++ b/mercurial/mpatch.c Fri Jul 22 17:28:05 2016 +0200
@@ -20,26 +20,15 @@
of the GNU General Public License, incorporated herein by reference.
*/
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
#include <stdlib.h>
#include <string.h>
-#include "util.h"
#include "bitmanipulation.h"
#include "compat.h"
-
-static char mpatch_doc[] = "Efficient binary patching.";
-static PyObject *mpatch_Error;
+#include "mpatch.h"
-struct mpatch_frag {
- int start, end, len;
- const char *data;
-};
-
-struct mpatch_flist {
- struct mpatch_frag *base, *head, *tail;
-};
+char *mpatch_errors[] = {NULL, "invalid patch", "patch cannot be decoded",
+ "no memory"};
struct mpatch_flist *lalloc(ssize_t size)
{
@@ -56,10 +45,7 @@
return a;
}
free(a);
- a = NULL;
}
- if (!PyErr_Occurred())
- PyErr_NoMemory();
return NULL;
}
@@ -202,7 +188,7 @@
}
/* decode a binary patch into a hunk list */
-struct mpatch_flist *mpatch_decode(const char *bin, ssize_t len)
+int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist **res)
{
struct mpatch_flist *l;
struct mpatch_frag *lt;
@@ -211,7 +197,7 @@
/* assume worst case size, we won't have many of these lists */
l = lalloc(len / 12 + 1);
if (!l)
- return NULL;
+ return MPATCH_ERR_NO_MEM;
lt = l->tail;
@@ -227,14 +213,13 @@
}
if (pos != len) {
- if (!PyErr_Occurred())
- PyErr_SetString(mpatch_Error, "patch cannot be decoded");
mpatch_lfree(l);
- return NULL;
+ return MPATCH_ERR_CANNOT_BE_DECODED;
}
l->tail = lt;
- return l;
+ *res = l;
+ return 0;
}
/* calculate the size of resultant text */
@@ -245,10 +230,7 @@
while (f != l->tail) {
if (f->start < last || f->end > len) {
- if (!PyErr_Occurred())
- PyErr_SetString(mpatch_Error,
- "invalid patch");
- return -1;
+ return MPATCH_ERR_INVALID_PATCH;
}
outlen += f->start - last;
last = f->end;
@@ -269,10 +251,7 @@
while (f != l->tail) {
if (f->start < last || f->end > len) {
- if (!PyErr_Occurred())
- PyErr_SetString(mpatch_Error,
- "invalid patch");
- return 0;
+ return MPATCH_ERR_INVALID_PATCH;
}
memcpy(p, orig + last, f->start - last);
p += f->start - last;
@@ -282,29 +261,24 @@
f++;
}
memcpy(p, orig + last, len - last);
- return 1;
+ return 0;
}
/* recursively generate a patch of all bins between start and end */
-struct mpatch_flist *mpatch_fold(PyObject *bins, ssize_t start,
- ssize_t end)
+struct mpatch_flist *mpatch_fold(void *bins,
+ struct mpatch_flist* (*get_next_item)(void*, ssize_t),
+ ssize_t start, ssize_t end)
{
- ssize_t len, blen;
- const char *buffer;
+ ssize_t len;
if (start + 1 == end) {
/* trivial case, output a decoded list */
- PyObject *tmp = PyList_GetItem(bins, start);
- if (!tmp)
- return NULL;
- if (PyObject_AsCharBuffer(tmp, &buffer, &blen))
- return NULL;
- return mpatch_decode(buffer, blen);
+ return get_next_item(bins, start);
}
/* divide and conquer, memory management is elsewhere */
len = (end - start) / 2;
- return combine(mpatch_fold(bins, start, start + len),
- mpatch_fold(bins, start + len, end));
+ return combine(mpatch_fold(bins, get_next_item, start, start + len),
+ mpatch_fold(bins, get_next_item, start + len, end));
}
--- a/mercurial/mpatch.h Mon Jul 18 19:02:30 2016 +0200
+++ b/mercurial/mpatch.h Fri Jul 22 17:28:05 2016 +0200
@@ -1,6 +1,12 @@
#ifndef _HG_MPATCH_H_
#define _HG_MPATCH_H_
+extern char *mpatch_errors[];
+
+#define MPATCH_ERR_NO_MEM -3
+#define MPATCH_ERR_CANNOT_BE_DECODED -2
+#define MPATCH_ERR_INVALID_PATCH -1
+
struct mpatch_frag {
int start, end, len;
const char *data;
@@ -15,6 +21,8 @@
void mpatch_lfree(struct mpatch_flist *a);
int mpatch_apply(char *buf, const char *orig, ssize_t len,
struct mpatch_flist *l);
-struct mpatch_flist *mpatch_fold(void *bins, ssize_t start, ssize_t end);
+struct mpatch_flist *mpatch_fold(void *bins,
+ struct mpatch_flist* (*get_next_item)(void*, ssize_t),
+ ssize_t start, ssize_t end);
#endif
--- a/mercurial/mpatch_module.c Mon Jul 18 19:02:30 2016 +0200
+++ b/mercurial/mpatch_module.c Fri Jul 22 17:28:05 2016 +0200
@@ -33,12 +33,33 @@
static char mpatch_doc[] = "Efficient binary patching.";
static PyObject *mpatch_Error;
+struct mpatch_flist *cpygetitem(void *bins, ssize_t pos)
+{
+ const char *buffer;
+ struct mpatch_flist *res;
+ ssize_t blen;
+ int r;
+
+ PyObject *tmp = PyList_GetItem((PyObject*)bins, pos);
+ if (!tmp)
+ return NULL;
+ if (PyObject_AsCharBuffer(tmp, &buffer, (Py_ssize_t*)&blen))
+ return NULL;
+ if ((r = mpatch_decode(buffer, blen, &res)) < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(mpatch_Error, mpatch_errors[-r]);
+ return NULL;
+ }
+ return res;
+}
+
static PyObject *
patches(PyObject *self, PyObject *args)
{
PyObject *text, *bins, *result;
struct mpatch_flist *patch;
const char *in;
+ int r;
char *out;
Py_ssize_t len, outlen, inlen;
@@ -55,12 +76,16 @@
if (PyObject_AsCharBuffer(text, &in, &inlen))
return NULL;
- patch = mpatch_fold(bins, 0, len);
- if (!patch)
+ patch = mpatch_fold(bins, cpygetitem, 0, len);
+ if (!patch) { /* error already set or memory error */
+ if (!PyErr_Occurred())
+ PyErr_NoMemory();
return NULL;
+ }
outlen = mpatch_calcsize(inlen, patch);
if (outlen < 0) {
+ r = (int)outlen;
result = NULL;
goto cleanup;
}
@@ -70,12 +95,14 @@
goto cleanup;
}
out = PyBytes_AsString(result);
- if (!mpatch_apply(out, in, inlen, patch)) {
+ if ((r = mpatch_apply(out, in, inlen, patch)) < 0) {
Py_DECREF(result);
result = NULL;
}
cleanup:
mpatch_lfree(patch);
+ if (!result && !PyErr_Occurred())
+ PyErr_SetString(mpatch_Error, mpatch_errors[-r]);
return result;
}