1 /* |
|
2 * diffhelpers.c - helper routines for mpatch |
|
3 * |
|
4 * Copyright 2007 Chris Mason <chris.mason@oracle.com> |
|
5 * |
|
6 * This software may be used and distributed according to the terms |
|
7 * of the GNU General Public License v2, incorporated herein by reference. |
|
8 */ |
|
9 |
|
10 #include <Python.h> |
|
11 #include <stdlib.h> |
|
12 #include <string.h> |
|
13 |
|
14 #include "util.h" |
|
15 |
|
16 static char diffhelpers_doc[] = "Efficient diff parsing"; |
|
17 static PyObject *diffhelpers_Error; |
|
18 |
|
19 |
|
20 /* fixup the last lines of a and b when the patch has no newline at eof */ |
|
21 static void _fix_newline(PyObject *hunk, PyObject *a, PyObject *b) |
|
22 { |
|
23 Py_ssize_t hunksz = PyList_Size(hunk); |
|
24 PyObject *s = PyList_GET_ITEM(hunk, hunksz-1); |
|
25 char *l = PyBytes_AsString(s); |
|
26 Py_ssize_t alen = PyList_Size(a); |
|
27 Py_ssize_t blen = PyList_Size(b); |
|
28 char c = l[0]; |
|
29 PyObject *hline; |
|
30 Py_ssize_t sz = PyBytes_GET_SIZE(s); |
|
31 |
|
32 if (sz > 1 && l[sz-2] == '\r') |
|
33 /* tolerate CRLF in last line */ |
|
34 sz -= 1; |
|
35 |
|
36 hline = PyBytes_FromStringAndSize(l, sz-1); |
|
37 if (!hline) { |
|
38 return; |
|
39 } |
|
40 |
|
41 if (c == ' ' || c == '+') { |
|
42 PyObject *rline = PyBytes_FromStringAndSize(l + 1, sz - 2); |
|
43 PyList_SetItem(b, blen-1, rline); |
|
44 } |
|
45 if (c == ' ' || c == '-') { |
|
46 Py_INCREF(hline); |
|
47 PyList_SetItem(a, alen-1, hline); |
|
48 } |
|
49 PyList_SetItem(hunk, hunksz-1, hline); |
|
50 } |
|
51 |
|
52 /* python callable form of _fix_newline */ |
|
53 static PyObject * |
|
54 fix_newline(PyObject *self, PyObject *args) |
|
55 { |
|
56 PyObject *hunk, *a, *b; |
|
57 if (!PyArg_ParseTuple(args, "OOO", &hunk, &a, &b)) |
|
58 return NULL; |
|
59 _fix_newline(hunk, a, b); |
|
60 return Py_BuildValue("l", 0); |
|
61 } |
|
62 |
|
63 #if (PY_VERSION_HEX < 0x02050000) |
|
64 static const char *addlines_format = "OOiiOO"; |
|
65 #else |
|
66 static const char *addlines_format = "OOnnOO"; |
|
67 #endif |
|
68 |
|
69 /* |
|
70 * read lines from fp into the hunk. The hunk is parsed into two arrays |
|
71 * a and b. a gets the old state of the text, b gets the new state |
|
72 * The control char from the hunk is saved when inserting into a, but not b |
|
73 * (for performance while deleting files) |
|
74 */ |
|
75 static PyObject * |
|
76 addlines(PyObject *self, PyObject *args) |
|
77 { |
|
78 |
|
79 PyObject *fp, *hunk, *a, *b, *x; |
|
80 Py_ssize_t i; |
|
81 Py_ssize_t lena, lenb; |
|
82 Py_ssize_t num; |
|
83 Py_ssize_t todoa, todob; |
|
84 char *s, c; |
|
85 PyObject *l; |
|
86 if (!PyArg_ParseTuple(args, addlines_format, |
|
87 &fp, &hunk, &lena, &lenb, &a, &b)) |
|
88 return NULL; |
|
89 |
|
90 while (1) { |
|
91 todoa = lena - PyList_Size(a); |
|
92 todob = lenb - PyList_Size(b); |
|
93 num = todoa > todob ? todoa : todob; |
|
94 if (num == 0) |
|
95 break; |
|
96 for (i = 0; i < num; i++) { |
|
97 x = PyFile_GetLine(fp, 0); |
|
98 s = PyBytes_AsString(x); |
|
99 c = *s; |
|
100 if (strcmp(s, "\\ No newline at end of file\n") == 0) { |
|
101 _fix_newline(hunk, a, b); |
|
102 continue; |
|
103 } |
|
104 if (c == '\n') { |
|
105 /* Some patches may be missing the control char |
|
106 * on empty lines. Supply a leading space. */ |
|
107 Py_DECREF(x); |
|
108 x = PyBytes_FromString(" \n"); |
|
109 } |
|
110 PyList_Append(hunk, x); |
|
111 if (c == '+') { |
|
112 l = PyBytes_FromString(s + 1); |
|
113 PyList_Append(b, l); |
|
114 Py_DECREF(l); |
|
115 } else if (c == '-') { |
|
116 PyList_Append(a, x); |
|
117 } else { |
|
118 l = PyBytes_FromString(s + 1); |
|
119 PyList_Append(b, l); |
|
120 Py_DECREF(l); |
|
121 PyList_Append(a, x); |
|
122 } |
|
123 Py_DECREF(x); |
|
124 } |
|
125 } |
|
126 return Py_BuildValue("l", 0); |
|
127 } |
|
128 |
|
129 /* |
|
130 * compare the lines in a with the lines in b. a is assumed to have |
|
131 * a control char at the start of each line, this char is ignored in the |
|
132 * compare |
|
133 */ |
|
134 static PyObject * |
|
135 testhunk(PyObject *self, PyObject *args) |
|
136 { |
|
137 |
|
138 PyObject *a, *b; |
|
139 long bstart; |
|
140 Py_ssize_t alen, blen; |
|
141 Py_ssize_t i; |
|
142 char *sa, *sb; |
|
143 |
|
144 if (!PyArg_ParseTuple(args, "OOl", &a, &b, &bstart)) |
|
145 return NULL; |
|
146 alen = PyList_Size(a); |
|
147 blen = PyList_Size(b); |
|
148 if (alen > blen - bstart || bstart < 0) { |
|
149 return Py_BuildValue("l", -1); |
|
150 } |
|
151 for (i = 0; i < alen; i++) { |
|
152 sa = PyBytes_AsString(PyList_GET_ITEM(a, i)); |
|
153 sb = PyBytes_AsString(PyList_GET_ITEM(b, i + bstart)); |
|
154 if (strcmp(sa + 1, sb) != 0) |
|
155 return Py_BuildValue("l", -1); |
|
156 } |
|
157 return Py_BuildValue("l", 0); |
|
158 } |
|
159 |
|
160 static PyMethodDef methods[] = { |
|
161 {"addlines", addlines, METH_VARARGS, "add lines to a hunk\n"}, |
|
162 {"fix_newline", fix_newline, METH_VARARGS, "fixup newline counters\n"}, |
|
163 {"testhunk", testhunk, METH_VARARGS, "test lines in a hunk\n"}, |
|
164 {NULL, NULL} |
|
165 }; |
|
166 |
|
167 #ifdef IS_PY3K |
|
168 static struct PyModuleDef diffhelpers_module = { |
|
169 PyModuleDef_HEAD_INIT, |
|
170 "diffhelpers", |
|
171 diffhelpers_doc, |
|
172 -1, |
|
173 methods |
|
174 }; |
|
175 |
|
176 PyMODINIT_FUNC PyInit_diffhelpers(void) |
|
177 { |
|
178 PyObject *m; |
|
179 |
|
180 m = PyModule_Create(&diffhelpers_module); |
|
181 if (m == NULL) |
|
182 return NULL; |
|
183 |
|
184 diffhelpers_Error = PyErr_NewException("diffhelpers.diffhelpersError", |
|
185 NULL, NULL); |
|
186 Py_INCREF(diffhelpers_Error); |
|
187 PyModule_AddObject(m, "diffhelpersError", diffhelpers_Error); |
|
188 |
|
189 return m; |
|
190 } |
|
191 #else |
|
192 PyMODINIT_FUNC |
|
193 initdiffhelpers(void) |
|
194 { |
|
195 Py_InitModule3("diffhelpers", methods, diffhelpers_doc); |
|
196 diffhelpers_Error = PyErr_NewException("diffhelpers.diffhelpersError", |
|
197 NULL, NULL); |
|
198 } |
|
199 #endif |
|