diff mercurial/diffhelpers.c @ 4897:4574925db5c0

Add Chris Mason's mpatch library. The original repo is http://oss.oracle.com/mercurial/mason/mpatch
author Bryan O'Sullivan <bos@serpentine.com>
date Tue, 17 Jul 2007 09:39:30 -0700
parents
children
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/mercurial/diffhelpers.c
@@ -0,0 +1,150 @@
+/*
+ * 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>
+
+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)
+{
+	int hunksz = PyList_Size(hunk);
+	PyObject *s = PyList_GET_ITEM(hunk, hunksz-1);
+	char *l = PyString_AS_STRING(s);
+	int sz = PyString_GET_SIZE(s);
+	int alen = PyList_Size(a);
+	int blen = PyList_Size(b);
+	char c = l[0];
+
+	PyObject *hline = PyString_FromStringAndSize(l, sz-1);
+	if (c == ' ' || c == '+') {
+		PyObject *rline = PyString_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);
+}
+
+/*
+ * 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;
+	int i;
+	int lena, lenb;
+	int num;
+	int todoa, todob;
+	char *s, c;
+	PyObject *l;
+	if (!PyArg_ParseTuple(args, "OOiiOO", &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 = PyString_AS_STRING(x);
+			c = *s;
+			if (strcmp(s, "\\ No newline at end of file\n") == 0) {
+				_fix_newline(hunk, a, b);
+				continue;
+			}
+			PyList_Append(hunk, x);
+			if (c == '+') {
+				l = PyString_FromString(s + 1);
+				PyList_Append(b, l);
+				Py_DECREF(l);
+			} else if (c == '-') {
+				PyList_Append(a, x);
+			} else {
+				l = PyString_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;
+	int alen, blen;
+	int 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) {
+		return Py_BuildValue("l", -1);
+	}
+	for (i = 0 ; i < alen ; i++) {
+		sa = PyString_AS_STRING(PyList_GET_ITEM(a, i));
+		sb = PyString_AS_STRING(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}
+};
+
+PyMODINIT_FUNC
+initdiffhelpers(void)
+{
+	Py_InitModule3("diffhelpers", methods, diffhelpers_doc);
+	diffhelpers_Error = PyErr_NewException("diffhelpers.diffhelpersError",
+	                                        NULL, NULL);
+}
+