##// END OF EJS Templates
diffhelpers: add version to help detect breaking binary changes
Jun Wu -
r32357:2f51f4c5 default
parent child Browse files
Show More
@@ -1,199 +1,204
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 Py_ssize_t hunksz = PyList_Size(hunk);
23 Py_ssize_t 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 Py_ssize_t alen = PyList_Size(a);
26 Py_ssize_t alen = PyList_Size(a);
27 Py_ssize_t blen = PyList_Size(b);
27 Py_ssize_t blen = PyList_Size(b);
28 char c = l[0];
28 char c = l[0];
29 PyObject *hline;
29 PyObject *hline;
30 Py_ssize_t sz = PyBytes_GET_SIZE(s);
30 Py_ssize_t 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 if (!hline) {
37 if (!hline) {
38 return;
38 return;
39 }
39 }
40
40
41 if (c == ' ' || c == '+') {
41 if (c == ' ' || c == '+') {
42 PyObject *rline = PyBytes_FromStringAndSize(l + 1, sz - 2);
42 PyObject *rline = PyBytes_FromStringAndSize(l + 1, sz - 2);
43 PyList_SetItem(b, blen-1, rline);
43 PyList_SetItem(b, blen-1, rline);
44 }
44 }
45 if (c == ' ' || c == '-') {
45 if (c == ' ' || c == '-') {
46 Py_INCREF(hline);
46 Py_INCREF(hline);
47 PyList_SetItem(a, alen-1, hline);
47 PyList_SetItem(a, alen-1, hline);
48 }
48 }
49 PyList_SetItem(hunk, hunksz-1, hline);
49 PyList_SetItem(hunk, hunksz-1, hline);
50 }
50 }
51
51
52 /* python callable form of _fix_newline */
52 /* python callable form of _fix_newline */
53 static PyObject *
53 static PyObject *
54 fix_newline(PyObject *self, PyObject *args)
54 fix_newline(PyObject *self, PyObject *args)
55 {
55 {
56 PyObject *hunk, *a, *b;
56 PyObject *hunk, *a, *b;
57 if (!PyArg_ParseTuple(args, "OOO", &hunk, &a, &b))
57 if (!PyArg_ParseTuple(args, "OOO", &hunk, &a, &b))
58 return NULL;
58 return NULL;
59 _fix_newline(hunk, a, b);
59 _fix_newline(hunk, a, b);
60 return Py_BuildValue("l", 0);
60 return Py_BuildValue("l", 0);
61 }
61 }
62
62
63 #if (PY_VERSION_HEX < 0x02050000)
63 #if (PY_VERSION_HEX < 0x02050000)
64 static const char *addlines_format = "OOiiOO";
64 static const char *addlines_format = "OOiiOO";
65 #else
65 #else
66 static const char *addlines_format = "OOnnOO";
66 static const char *addlines_format = "OOnnOO";
67 #endif
67 #endif
68
68
69 /*
69 /*
70 * read lines from fp into the hunk. The hunk is parsed into two arrays
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
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
72 * The control char from the hunk is saved when inserting into a, but not b
73 * (for performance while deleting files)
73 * (for performance while deleting files)
74 */
74 */
75 static PyObject *
75 static PyObject *
76 addlines(PyObject *self, PyObject *args)
76 addlines(PyObject *self, PyObject *args)
77 {
77 {
78
78
79 PyObject *fp, *hunk, *a, *b, *x;
79 PyObject *fp, *hunk, *a, *b, *x;
80 Py_ssize_t i;
80 Py_ssize_t i;
81 Py_ssize_t lena, lenb;
81 Py_ssize_t lena, lenb;
82 Py_ssize_t num;
82 Py_ssize_t num;
83 Py_ssize_t todoa, todob;
83 Py_ssize_t todoa, todob;
84 char *s, c;
84 char *s, c;
85 PyObject *l;
85 PyObject *l;
86 if (!PyArg_ParseTuple(args, addlines_format,
86 if (!PyArg_ParseTuple(args, addlines_format,
87 &fp, &hunk, &lena, &lenb, &a, &b))
87 &fp, &hunk, &lena, &lenb, &a, &b))
88 return NULL;
88 return NULL;
89
89
90 while (1) {
90 while (1) {
91 todoa = lena - PyList_Size(a);
91 todoa = lena - PyList_Size(a);
92 todob = lenb - PyList_Size(b);
92 todob = lenb - PyList_Size(b);
93 num = todoa > todob ? todoa : todob;
93 num = todoa > todob ? todoa : todob;
94 if (num == 0)
94 if (num == 0)
95 break;
95 break;
96 for (i = 0; i < num; i++) {
96 for (i = 0; i < num; i++) {
97 x = PyFile_GetLine(fp, 0);
97 x = PyFile_GetLine(fp, 0);
98 s = PyBytes_AsString(x);
98 s = PyBytes_AsString(x);
99 c = *s;
99 c = *s;
100 if (strcmp(s, "\\ No newline at end of file\n") == 0) {
100 if (strcmp(s, "\\ No newline at end of file\n") == 0) {
101 _fix_newline(hunk, a, b);
101 _fix_newline(hunk, a, b);
102 continue;
102 continue;
103 }
103 }
104 if (c == '\n') {
104 if (c == '\n') {
105 /* Some patches may be missing the control char
105 /* Some patches may be missing the control char
106 * on empty lines. Supply a leading space. */
106 * on empty lines. Supply a leading space. */
107 Py_DECREF(x);
107 Py_DECREF(x);
108 x = PyBytes_FromString(" \n");
108 x = PyBytes_FromString(" \n");
109 }
109 }
110 PyList_Append(hunk, x);
110 PyList_Append(hunk, x);
111 if (c == '+') {
111 if (c == '+') {
112 l = PyBytes_FromString(s + 1);
112 l = PyBytes_FromString(s + 1);
113 PyList_Append(b, l);
113 PyList_Append(b, l);
114 Py_DECREF(l);
114 Py_DECREF(l);
115 } else if (c == '-') {
115 } else if (c == '-') {
116 PyList_Append(a, x);
116 PyList_Append(a, x);
117 } else {
117 } else {
118 l = PyBytes_FromString(s + 1);
118 l = PyBytes_FromString(s + 1);
119 PyList_Append(b, l);
119 PyList_Append(b, l);
120 Py_DECREF(l);
120 Py_DECREF(l);
121 PyList_Append(a, x);
121 PyList_Append(a, x);
122 }
122 }
123 Py_DECREF(x);
123 Py_DECREF(x);
124 }
124 }
125 }
125 }
126 return Py_BuildValue("l", 0);
126 return Py_BuildValue("l", 0);
127 }
127 }
128
128
129 /*
129 /*
130 * compare the lines in a with the lines in b. a is assumed to have
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
131 * a control char at the start of each line, this char is ignored in the
132 * compare
132 * compare
133 */
133 */
134 static PyObject *
134 static PyObject *
135 testhunk(PyObject *self, PyObject *args)
135 testhunk(PyObject *self, PyObject *args)
136 {
136 {
137
137
138 PyObject *a, *b;
138 PyObject *a, *b;
139 long bstart;
139 long bstart;
140 Py_ssize_t alen, blen;
140 Py_ssize_t alen, blen;
141 Py_ssize_t i;
141 Py_ssize_t i;
142 char *sa, *sb;
142 char *sa, *sb;
143
143
144 if (!PyArg_ParseTuple(args, "OOl", &a, &b, &bstart))
144 if (!PyArg_ParseTuple(args, "OOl", &a, &b, &bstart))
145 return NULL;
145 return NULL;
146 alen = PyList_Size(a);
146 alen = PyList_Size(a);
147 blen = PyList_Size(b);
147 blen = PyList_Size(b);
148 if (alen > blen - bstart || bstart < 0) {
148 if (alen > blen - bstart || bstart < 0) {
149 return Py_BuildValue("l", -1);
149 return Py_BuildValue("l", -1);
150 }
150 }
151 for (i = 0; i < alen; i++) {
151 for (i = 0; i < alen; i++) {
152 sa = PyBytes_AsString(PyList_GET_ITEM(a, i));
152 sa = PyBytes_AsString(PyList_GET_ITEM(a, i));
153 sb = PyBytes_AsString(PyList_GET_ITEM(b, i + bstart));
153 sb = PyBytes_AsString(PyList_GET_ITEM(b, i + bstart));
154 if (strcmp(sa + 1, sb) != 0)
154 if (strcmp(sa + 1, sb) != 0)
155 return Py_BuildValue("l", -1);
155 return Py_BuildValue("l", -1);
156 }
156 }
157 return Py_BuildValue("l", 0);
157 return Py_BuildValue("l", 0);
158 }
158 }
159
159
160 static PyMethodDef methods[] = {
160 static PyMethodDef methods[] = {
161 {"addlines", addlines, METH_VARARGS, "add lines to a hunk\n"},
161 {"addlines", addlines, METH_VARARGS, "add lines to a hunk\n"},
162 {"fix_newline", fix_newline, METH_VARARGS, "fixup newline counters\n"},
162 {"fix_newline", fix_newline, METH_VARARGS, "fixup newline counters\n"},
163 {"testhunk", testhunk, METH_VARARGS, "test lines in a hunk\n"},
163 {"testhunk", testhunk, METH_VARARGS, "test lines in a hunk\n"},
164 {NULL, NULL}
164 {NULL, NULL}
165 };
165 };
166
166
167 static const int version = 1;
168
167 #ifdef IS_PY3K
169 #ifdef IS_PY3K
168 static struct PyModuleDef diffhelpers_module = {
170 static struct PyModuleDef diffhelpers_module = {
169 PyModuleDef_HEAD_INIT,
171 PyModuleDef_HEAD_INIT,
170 "diffhelpers",
172 "diffhelpers",
171 diffhelpers_doc,
173 diffhelpers_doc,
172 -1,
174 -1,
173 methods
175 methods
174 };
176 };
175
177
176 PyMODINIT_FUNC PyInit_diffhelpers(void)
178 PyMODINIT_FUNC PyInit_diffhelpers(void)
177 {
179 {
178 PyObject *m;
180 PyObject *m;
179
181
180 m = PyModule_Create(&diffhelpers_module);
182 m = PyModule_Create(&diffhelpers_module);
181 if (m == NULL)
183 if (m == NULL)
182 return NULL;
184 return NULL;
183
185
184 diffhelpers_Error = PyErr_NewException("diffhelpers.diffhelpersError",
186 diffhelpers_Error = PyErr_NewException("diffhelpers.diffhelpersError",
185 NULL, NULL);
187 NULL, NULL);
186 Py_INCREF(diffhelpers_Error);
188 Py_INCREF(diffhelpers_Error);
187 PyModule_AddObject(m, "diffhelpersError", diffhelpers_Error);
189 PyModule_AddObject(m, "diffhelpersError", diffhelpers_Error);
190 PyModule_AddIntConstant(m, "version", version);
188
191
189 return m;
192 return m;
190 }
193 }
191 #else
194 #else
192 PyMODINIT_FUNC
195 PyMODINIT_FUNC
193 initdiffhelpers(void)
196 initdiffhelpers(void)
194 {
197 {
195 Py_InitModule3("diffhelpers", methods, diffhelpers_doc);
198 PyObject *m;
199 m = Py_InitModule3("diffhelpers", methods, diffhelpers_doc);
196 diffhelpers_Error = PyErr_NewException("diffhelpers.diffhelpersError",
200 diffhelpers_Error = PyErr_NewException("diffhelpers.diffhelpersError",
197 NULL, NULL);
201 NULL, NULL);
202 PyModule_AddIntConstant(m, "version", version);
198 }
203 }
199 #endif
204 #endif
General Comments 0
You need to be logged in to leave comments. Login now