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