diff --git a/mercurial/cext/bdiff.c b/mercurial/cext/bdiff.c --- a/mercurial/cext/bdiff.c +++ b/mercurial/cext/bdiff.c @@ -182,6 +182,55 @@ return result ? result : PyErr_NoMemory(); } +bool sliceintolist(PyObject *list, Py_ssize_t destidx, + const char *source, Py_ssize_t len) { + PyObject *sliced = PyString_FromStringAndSize(source, len); + if (sliced == NULL) + return false; + PyList_SetItem(list, destidx, sliced); + return true; +} + +static PyObject *splitnewlines(PyObject *self, PyObject *args) +{ + const char *text; + int i, start = 0; + Py_ssize_t nelts = 0, size; + PyObject *result; + + if (!PyArg_ParseTuple(args, "s#", &text, &size)) + goto abort; + if (!size) { + return PyList_New(0); + } + /* This loops to size-1 because if the last byte is a newline, + * we don't want to perform a split there. */ + for (i = 0; i < size - 1; ++i) { + if (text[i] == '\n') { + ++nelts; + } + } + if ((result = PyList_New(nelts+1)) == NULL) + goto abort; + nelts = 0; + for (i = 0; i < size - 1; ++i) { + if (text[i] == '\n') { + if (!sliceintolist( + result, nelts++, text+start, i-start+1)) + goto abort; + start = i+1; + } + } + if (start < size) { + if (!sliceintolist(result, nelts++, text+start, size-start)) + goto abort; + } + return result; +abort: + Py_XDECREF(result); + return NULL; +} + static char mdiff_doc[] = "Efficient binary diff."; @@ -189,6 +238,8 @@ {"bdiff", bdiff, METH_VARARGS, "calculate a binary diff\n"}, {"blocks", blocks, METH_VARARGS, "find a list of matching lines\n"}, {"fixws", fixws, METH_VARARGS, "normalize diff whitespaces\n"}, + {"splitnewlines", splitnewlines, METH_VARARGS, + "like str.splitlines, but only split on newlines\n"}, {NULL, NULL} }; diff --git a/mercurial/mdiff.py b/mercurial/mdiff.py --- a/mercurial/mdiff.py +++ b/mercurial/mdiff.py @@ -40,6 +40,8 @@ lines[-1] = lines[-1][:-1] return lines +splitnewlines = getattr(bdiff, 'splitnewlines', splitnewlines) + class diffopts(object): '''context is the number of context lines text treats all files as text