|
|
/*
|
|
|
* diffhelpers.c - helper routines for mpatch
|
|
|
*
|
|
|
* Copyright 2007 Chris Mason <chris.mason@oracle.com>
|
|
|
*
|
|
|
* This software may be used and distributed according to the terms
|
|
|
* of the GNU General Public License v2, incorporated herein by reference.
|
|
|
*/
|
|
|
|
|
|
#include <Python.h>
|
|
|
#include <stdlib.h>
|
|
|
#include <string.h>
|
|
|
|
|
|
#include "util.h"
|
|
|
|
|
|
static char diffhelpers_doc[] = "Efficient diff parsing";
|
|
|
static PyObject *diffhelpers_Error;
|
|
|
|
|
|
|
|
|
/* fixup the last lines of a and b when the patch has no newline at eof */
|
|
|
static void _fix_newline(PyObject *hunk, PyObject *a, PyObject *b)
|
|
|
{
|
|
|
Py_ssize_t hunksz = PyList_Size(hunk);
|
|
|
PyObject *s = PyList_GET_ITEM(hunk, hunksz-1);
|
|
|
char *l = PyBytes_AsString(s);
|
|
|
Py_ssize_t alen = PyList_Size(a);
|
|
|
Py_ssize_t blen = PyList_Size(b);
|
|
|
char c = l[0];
|
|
|
PyObject *hline;
|
|
|
Py_ssize_t sz = PyBytes_GET_SIZE(s);
|
|
|
|
|
|
if (sz > 1 && l[sz-2] == '\r')
|
|
|
/* tolerate CRLF in last line */
|
|
|
sz -= 1;
|
|
|
|
|
|
hline = PyBytes_FromStringAndSize(l, sz-1);
|
|
|
if (!hline) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (c == ' ' || c == '+') {
|
|
|
PyObject *rline = PyBytes_FromStringAndSize(l + 1, sz - 2);
|
|
|
PyList_SetItem(b, blen-1, rline);
|
|
|
}
|
|
|
if (c == ' ' || c == '-') {
|
|
|
Py_INCREF(hline);
|
|
|
PyList_SetItem(a, alen-1, hline);
|
|
|
}
|
|
|
PyList_SetItem(hunk, hunksz-1, hline);
|
|
|
}
|
|
|
|
|
|
/* python callable form of _fix_newline */
|
|
|
static PyObject *
|
|
|
fix_newline(PyObject *self, PyObject *args)
|
|
|
{
|
|
|
PyObject *hunk, *a, *b;
|
|
|
if (!PyArg_ParseTuple(args, "OOO", &hunk, &a, &b))
|
|
|
return NULL;
|
|
|
_fix_newline(hunk, a, b);
|
|
|
return Py_BuildValue("l", 0);
|
|
|
}
|
|
|
|
|
|
#if (PY_VERSION_HEX < 0x02050000)
|
|
|
static const char *addlines_format = "OOiiOO";
|
|
|
#else
|
|
|
static const char *addlines_format = "OOnnOO";
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
|
* read lines from fp into the hunk. The hunk is parsed into two arrays
|
|
|
* a and b. a gets the old state of the text, b gets the new state
|
|
|
* The control char from the hunk is saved when inserting into a, but not b
|
|
|
* (for performance while deleting files)
|
|
|
*/
|
|
|
static PyObject *
|
|
|
addlines(PyObject *self, PyObject *args)
|
|
|
{
|
|
|
|
|
|
PyObject *fp, *hunk, *a, *b, *x;
|
|
|
Py_ssize_t i;
|
|
|
Py_ssize_t lena, lenb;
|
|
|
Py_ssize_t num;
|
|
|
Py_ssize_t todoa, todob;
|
|
|
char *s, c;
|
|
|
PyObject *l;
|
|
|
if (!PyArg_ParseTuple(args, addlines_format,
|
|
|
&fp, &hunk, &lena, &lenb, &a, &b))
|
|
|
return NULL;
|
|
|
|
|
|
while (1) {
|
|
|
todoa = lena - PyList_Size(a);
|
|
|
todob = lenb - PyList_Size(b);
|
|
|
num = todoa > todob ? todoa : todob;
|
|
|
if (num == 0)
|
|
|
break;
|
|
|
for (i = 0; i < num; i++) {
|
|
|
x = PyFile_GetLine(fp, 0);
|
|
|
s = PyBytes_AsString(x);
|
|
|
c = *s;
|
|
|
if (strcmp(s, "\\ No newline at end of file\n") == 0) {
|
|
|
_fix_newline(hunk, a, b);
|
|
|
continue;
|
|
|
}
|
|
|
if (c == '\n') {
|
|
|
/* Some patches may be missing the control char
|
|
|
* on empty lines. Supply a leading space. */
|
|
|
Py_DECREF(x);
|
|
|
x = PyBytes_FromString(" \n");
|
|
|
}
|
|
|
PyList_Append(hunk, x);
|
|
|
if (c == '+') {
|
|
|
l = PyBytes_FromString(s + 1);
|
|
|
PyList_Append(b, l);
|
|
|
Py_DECREF(l);
|
|
|
} else if (c == '-') {
|
|
|
PyList_Append(a, x);
|
|
|
} else {
|
|
|
l = PyBytes_FromString(s + 1);
|
|
|
PyList_Append(b, l);
|
|
|
Py_DECREF(l);
|
|
|
PyList_Append(a, x);
|
|
|
}
|
|
|
Py_DECREF(x);
|
|
|
}
|
|
|
}
|
|
|
return Py_BuildValue("l", 0);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* compare the lines in a with the lines in b. a is assumed to have
|
|
|
* a control char at the start of each line, this char is ignored in the
|
|
|
* compare
|
|
|
*/
|
|
|
static PyObject *
|
|
|
testhunk(PyObject *self, PyObject *args)
|
|
|
{
|
|
|
|
|
|
PyObject *a, *b;
|
|
|
long bstart;
|
|
|
Py_ssize_t alen, blen;
|
|
|
Py_ssize_t i;
|
|
|
char *sa, *sb;
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "OOl", &a, &b, &bstart))
|
|
|
return NULL;
|
|
|
alen = PyList_Size(a);
|
|
|
blen = PyList_Size(b);
|
|
|
if (alen > blen - bstart || bstart < 0) {
|
|
|
return Py_BuildValue("l", -1);
|
|
|
}
|
|
|
for (i = 0; i < alen; i++) {
|
|
|
sa = PyBytes_AsString(PyList_GET_ITEM(a, i));
|
|
|
sb = PyBytes_AsString(PyList_GET_ITEM(b, i + bstart));
|
|
|
if (strcmp(sa + 1, sb) != 0)
|
|
|
return Py_BuildValue("l", -1);
|
|
|
}
|
|
|
return Py_BuildValue("l", 0);
|
|
|
}
|
|
|
|
|
|
static PyMethodDef methods[] = {
|
|
|
{"addlines", addlines, METH_VARARGS, "add lines to a hunk\n"},
|
|
|
{"fix_newline", fix_newline, METH_VARARGS, "fixup newline counters\n"},
|
|
|
{"testhunk", testhunk, METH_VARARGS, "test lines in a hunk\n"},
|
|
|
{NULL, NULL}
|
|
|
};
|
|
|
|
|
|
#ifdef IS_PY3K
|
|
|
static struct PyModuleDef diffhelpers_module = {
|
|
|
PyModuleDef_HEAD_INIT,
|
|
|
"diffhelpers",
|
|
|
diffhelpers_doc,
|
|
|
-1,
|
|
|
methods
|
|
|
};
|
|
|
|
|
|
PyMODINIT_FUNC PyInit_diffhelpers(void)
|
|
|
{
|
|
|
PyObject *m;
|
|
|
|
|
|
m = PyModule_Create(&diffhelpers_module);
|
|
|
if (m == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
diffhelpers_Error = PyErr_NewException("diffhelpers.diffhelpersError",
|
|
|
NULL, NULL);
|
|
|
Py_INCREF(diffhelpers_Error);
|
|
|
PyModule_AddObject(m, "diffhelpersError", diffhelpers_Error);
|
|
|
|
|
|
return m;
|
|
|
}
|
|
|
#else
|
|
|
PyMODINIT_FUNC
|
|
|
initdiffhelpers(void)
|
|
|
{
|
|
|
Py_InitModule3("diffhelpers", methods, diffhelpers_doc);
|
|
|
diffhelpers_Error = PyErr_NewException("diffhelpers.diffhelpersError",
|
|
|
NULL, NULL);
|
|
|
}
|
|
|
#endif
|
|
|
|