##// END OF EJS Templates
cext: remove some conditional preprocessor defines...
Gregory Szorc -
r49668:be3af7eb default
parent child Browse files
Show More
@@ -1,1013 +1,999 b''
1 /*
1 /*
2 * manifest.c - manifest type that does on-demand parsing.
2 * manifest.c - manifest type that does on-demand parsing.
3 *
3 *
4 * Copyright 2015, Google Inc.
4 * Copyright 2015, Google Inc.
5 *
5 *
6 * This software may be used and distributed according to the terms of
6 * This software may be used and distributed according to the terms of
7 * the GNU General Public License, incorporated herein by reference.
7 * the GNU General Public License, incorporated herein by reference.
8 */
8 */
9 #include <Python.h>
9 #include <Python.h>
10
10
11 #include <assert.h>
11 #include <assert.h>
12 #include <stdlib.h>
12 #include <stdlib.h>
13 #include <string.h>
13 #include <string.h>
14
14
15 #include "charencode.h"
15 #include "charencode.h"
16 #include "util.h"
16 #include "util.h"
17
17
18 #define DEFAULT_LINES 100000
18 #define DEFAULT_LINES 100000
19
19
20 typedef struct {
20 typedef struct {
21 char *start;
21 char *start;
22 Py_ssize_t len; /* length of line including terminal newline */
22 Py_ssize_t len; /* length of line including terminal newline */
23 char hash_suffix;
23 char hash_suffix;
24 bool from_malloc;
24 bool from_malloc;
25 bool deleted;
25 bool deleted;
26 } line;
26 } line;
27
27
28 typedef struct {
28 typedef struct {
29 PyObject_HEAD
29 PyObject_HEAD
30 PyObject *pydata;
30 PyObject *pydata;
31 Py_ssize_t nodelen;
31 Py_ssize_t nodelen;
32 line *lines;
32 line *lines;
33 int numlines; /* number of line entries */
33 int numlines; /* number of line entries */
34 int livelines; /* number of non-deleted lines */
34 int livelines; /* number of non-deleted lines */
35 int maxlines; /* allocated number of lines */
35 int maxlines; /* allocated number of lines */
36 bool dirty;
36 bool dirty;
37 } lazymanifest;
37 } lazymanifest;
38
38
39 #define MANIFEST_OOM -1
39 #define MANIFEST_OOM -1
40 #define MANIFEST_NOT_SORTED -2
40 #define MANIFEST_NOT_SORTED -2
41 #define MANIFEST_MALFORMED -3
41 #define MANIFEST_MALFORMED -3
42 #define MANIFEST_BOGUS_FILENAME -4
42 #define MANIFEST_BOGUS_FILENAME -4
43 #define MANIFEST_TOO_SHORT_LINE -5
43 #define MANIFEST_TOO_SHORT_LINE -5
44
44
45 /* get the length of the path for a line */
45 /* get the length of the path for a line */
46 static Py_ssize_t pathlen(line *l)
46 static Py_ssize_t pathlen(line *l)
47 {
47 {
48 const char *end = memchr(l->start, '\0', l->len);
48 const char *end = memchr(l->start, '\0', l->len);
49 return (end) ? (Py_ssize_t)(end - l->start) : l->len;
49 return (end) ? (Py_ssize_t)(end - l->start) : l->len;
50 }
50 }
51
51
52 /* get the node value of a single line */
52 /* get the node value of a single line */
53 static PyObject *nodeof(Py_ssize_t nodelen, line *l, char *flag)
53 static PyObject *nodeof(Py_ssize_t nodelen, line *l, char *flag)
54 {
54 {
55 char *s = l->start;
55 char *s = l->start;
56 Py_ssize_t llen = pathlen(l);
56 Py_ssize_t llen = pathlen(l);
57 Py_ssize_t hlen = l->len - llen - 2;
57 Py_ssize_t hlen = l->len - llen - 2;
58 PyObject *hash;
58 PyObject *hash;
59 if (llen + 1 + 40 + 1 > l->len) { /* path '\0' hash '\n' */
59 if (llen + 1 + 40 + 1 > l->len) { /* path '\0' hash '\n' */
60 PyErr_SetString(PyExc_ValueError, "manifest line too short");
60 PyErr_SetString(PyExc_ValueError, "manifest line too short");
61 return NULL;
61 return NULL;
62 }
62 }
63 /* Detect flags after the hash first. */
63 /* Detect flags after the hash first. */
64 switch (s[llen + hlen]) {
64 switch (s[llen + hlen]) {
65 case 'l':
65 case 'l':
66 case 't':
66 case 't':
67 case 'x':
67 case 'x':
68 *flag = s[llen + hlen];
68 *flag = s[llen + hlen];
69 --hlen;
69 --hlen;
70 break;
70 break;
71 default:
71 default:
72 *flag = '\0';
72 *flag = '\0';
73 break;
73 break;
74 }
74 }
75
75
76 if (hlen != 2 * nodelen) {
76 if (hlen != 2 * nodelen) {
77 PyErr_SetString(PyExc_ValueError, "invalid node length in manifest");
77 PyErr_SetString(PyExc_ValueError, "invalid node length in manifest");
78 return NULL;
78 return NULL;
79 }
79 }
80 hash = unhexlify(s + llen + 1, nodelen * 2);
80 hash = unhexlify(s + llen + 1, nodelen * 2);
81 if (!hash) {
81 if (!hash) {
82 return NULL;
82 return NULL;
83 }
83 }
84 if (l->hash_suffix != '\0') {
84 if (l->hash_suffix != '\0') {
85 char newhash[33];
85 char newhash[33];
86 memcpy(newhash, PyBytes_AsString(hash), nodelen);
86 memcpy(newhash, PyBytes_AsString(hash), nodelen);
87 Py_DECREF(hash);
87 Py_DECREF(hash);
88 newhash[nodelen] = l->hash_suffix;
88 newhash[nodelen] = l->hash_suffix;
89 hash = PyBytes_FromStringAndSize(newhash, nodelen + 1);
89 hash = PyBytes_FromStringAndSize(newhash, nodelen + 1);
90 }
90 }
91 return hash;
91 return hash;
92 }
92 }
93
93
94 /* get the node hash and flags of a line as a tuple */
94 /* get the node hash and flags of a line as a tuple */
95 static PyObject *hashflags(Py_ssize_t nodelen, line *l)
95 static PyObject *hashflags(Py_ssize_t nodelen, line *l)
96 {
96 {
97 char flag;
97 char flag;
98 PyObject *hash = nodeof(nodelen, l, &flag);
98 PyObject *hash = nodeof(nodelen, l, &flag);
99 PyObject *flags;
99 PyObject *flags;
100 PyObject *tup;
100 PyObject *tup;
101
101
102 if (!hash)
102 if (!hash)
103 return NULL;
103 return NULL;
104 flags = PyBytes_FromStringAndSize(&flag, flag ? 1 : 0);
104 flags = PyBytes_FromStringAndSize(&flag, flag ? 1 : 0);
105 if (!flags) {
105 if (!flags) {
106 Py_DECREF(hash);
106 Py_DECREF(hash);
107 return NULL;
107 return NULL;
108 }
108 }
109 tup = PyTuple_Pack(2, hash, flags);
109 tup = PyTuple_Pack(2, hash, flags);
110 Py_DECREF(flags);
110 Py_DECREF(flags);
111 Py_DECREF(hash);
111 Py_DECREF(hash);
112 return tup;
112 return tup;
113 }
113 }
114
114
115 /* if we're about to run out of space in the line index, add more */
115 /* if we're about to run out of space in the line index, add more */
116 static bool realloc_if_full(lazymanifest *self)
116 static bool realloc_if_full(lazymanifest *self)
117 {
117 {
118 if (self->numlines == self->maxlines) {
118 if (self->numlines == self->maxlines) {
119 self->maxlines *= 2;
119 self->maxlines *= 2;
120 self->lines = realloc(self->lines, self->maxlines * sizeof(line));
120 self->lines = realloc(self->lines, self->maxlines * sizeof(line));
121 }
121 }
122 return !!self->lines;
122 return !!self->lines;
123 }
123 }
124
124
125 /*
125 /*
126 * Find the line boundaries in the manifest that 'data' points to and store
126 * Find the line boundaries in the manifest that 'data' points to and store
127 * information about each line in 'self'.
127 * information about each line in 'self'.
128 */
128 */
129 static int find_lines(lazymanifest *self, char *data, Py_ssize_t len)
129 static int find_lines(lazymanifest *self, char *data, Py_ssize_t len)
130 {
130 {
131 char *prev = NULL;
131 char *prev = NULL;
132 while (len > 0) {
132 while (len > 0) {
133 line *l;
133 line *l;
134 char *next;
134 char *next;
135 if (*data == '\0') {
135 if (*data == '\0') {
136 /* It's implausible there's no filename, don't
136 /* It's implausible there's no filename, don't
137 * even bother looking for the newline. */
137 * even bother looking for the newline. */
138 return MANIFEST_BOGUS_FILENAME;
138 return MANIFEST_BOGUS_FILENAME;
139 }
139 }
140 next = memchr(data, '\n', len);
140 next = memchr(data, '\n', len);
141 if (!next) {
141 if (!next) {
142 return MANIFEST_MALFORMED;
142 return MANIFEST_MALFORMED;
143 }
143 }
144 if ((next - data) < 42) {
144 if ((next - data) < 42) {
145 /* We should have at least 42 bytes in a line:
145 /* We should have at least 42 bytes in a line:
146 1 byte filename
146 1 byte filename
147 1 NUL
147 1 NUL
148 40 bytes of hash
148 40 bytes of hash
149 so we can give up here.
149 so we can give up here.
150 */
150 */
151 return MANIFEST_TOO_SHORT_LINE;
151 return MANIFEST_TOO_SHORT_LINE;
152 }
152 }
153 next++; /* advance past newline */
153 next++; /* advance past newline */
154 if (prev && strcmp(prev, data) > -1) {
154 if (prev && strcmp(prev, data) > -1) {
155 /* This data isn't sorted, so we have to abort. */
155 /* This data isn't sorted, so we have to abort. */
156 return MANIFEST_NOT_SORTED;
156 return MANIFEST_NOT_SORTED;
157 }
157 }
158 if (!realloc_if_full(self)) {
158 if (!realloc_if_full(self)) {
159 return MANIFEST_OOM; /* no memory */
159 return MANIFEST_OOM; /* no memory */
160 }
160 }
161 l = self->lines + ((self->numlines)++);
161 l = self->lines + ((self->numlines)++);
162 l->start = data;
162 l->start = data;
163 l->len = next - data;
163 l->len = next - data;
164 l->hash_suffix = '\0';
164 l->hash_suffix = '\0';
165 l->from_malloc = false;
165 l->from_malloc = false;
166 l->deleted = false;
166 l->deleted = false;
167 len = len - l->len;
167 len = len - l->len;
168 prev = data;
168 prev = data;
169 data = next;
169 data = next;
170 }
170 }
171 self->livelines = self->numlines;
171 self->livelines = self->numlines;
172 return 0;
172 return 0;
173 }
173 }
174
174
175 static void lazymanifest_init_early(lazymanifest *self)
175 static void lazymanifest_init_early(lazymanifest *self)
176 {
176 {
177 self->pydata = NULL;
177 self->pydata = NULL;
178 self->lines = NULL;
178 self->lines = NULL;
179 self->numlines = 0;
179 self->numlines = 0;
180 self->maxlines = 0;
180 self->maxlines = 0;
181 }
181 }
182
182
183 static int lazymanifest_init(lazymanifest *self, PyObject *args)
183 static int lazymanifest_init(lazymanifest *self, PyObject *args)
184 {
184 {
185 char *data;
185 char *data;
186 Py_ssize_t nodelen, len;
186 Py_ssize_t nodelen, len;
187 int err, ret;
187 int err, ret;
188 PyObject *pydata;
188 PyObject *pydata;
189
189
190 lazymanifest_init_early(self);
190 lazymanifest_init_early(self);
191 if (!PyArg_ParseTuple(args, "nS", &nodelen, &pydata)) {
191 if (!PyArg_ParseTuple(args, "nS", &nodelen, &pydata)) {
192 return -1;
192 return -1;
193 }
193 }
194 if (nodelen != 20 && nodelen != 32) {
194 if (nodelen != 20 && nodelen != 32) {
195 /* See fixed buffer in nodeof */
195 /* See fixed buffer in nodeof */
196 PyErr_Format(PyExc_ValueError, "Unsupported node length");
196 PyErr_Format(PyExc_ValueError, "Unsupported node length");
197 return -1;
197 return -1;
198 }
198 }
199 self->nodelen = nodelen;
199 self->nodelen = nodelen;
200 self->dirty = false;
200 self->dirty = false;
201
201
202 err = PyBytes_AsStringAndSize(pydata, &data, &len);
202 err = PyBytes_AsStringAndSize(pydata, &data, &len);
203 if (err == -1)
203 if (err == -1)
204 return -1;
204 return -1;
205 self->pydata = pydata;
205 self->pydata = pydata;
206 Py_INCREF(self->pydata);
206 Py_INCREF(self->pydata);
207 Py_BEGIN_ALLOW_THREADS
207 Py_BEGIN_ALLOW_THREADS
208 self->lines = malloc(DEFAULT_LINES * sizeof(line));
208 self->lines = malloc(DEFAULT_LINES * sizeof(line));
209 self->maxlines = DEFAULT_LINES;
209 self->maxlines = DEFAULT_LINES;
210 self->numlines = 0;
210 self->numlines = 0;
211 if (!self->lines)
211 if (!self->lines)
212 ret = MANIFEST_OOM;
212 ret = MANIFEST_OOM;
213 else
213 else
214 ret = find_lines(self, data, len);
214 ret = find_lines(self, data, len);
215 Py_END_ALLOW_THREADS
215 Py_END_ALLOW_THREADS
216 switch (ret) {
216 switch (ret) {
217 case 0:
217 case 0:
218 break;
218 break;
219 case MANIFEST_OOM:
219 case MANIFEST_OOM:
220 PyErr_NoMemory();
220 PyErr_NoMemory();
221 break;
221 break;
222 case MANIFEST_NOT_SORTED:
222 case MANIFEST_NOT_SORTED:
223 PyErr_Format(PyExc_ValueError,
223 PyErr_Format(PyExc_ValueError,
224 "Manifest lines not in sorted order.");
224 "Manifest lines not in sorted order.");
225 break;
225 break;
226 case MANIFEST_MALFORMED:
226 case MANIFEST_MALFORMED:
227 PyErr_Format(PyExc_ValueError,
227 PyErr_Format(PyExc_ValueError,
228 "Manifest did not end in a newline.");
228 "Manifest did not end in a newline.");
229 break;
229 break;
230 case MANIFEST_BOGUS_FILENAME:
230 case MANIFEST_BOGUS_FILENAME:
231 PyErr_Format(
231 PyErr_Format(
232 PyExc_ValueError,
232 PyExc_ValueError,
233 "Manifest had an entry with a zero-length filename.");
233 "Manifest had an entry with a zero-length filename.");
234 break;
234 break;
235 case MANIFEST_TOO_SHORT_LINE:
235 case MANIFEST_TOO_SHORT_LINE:
236 PyErr_Format(
236 PyErr_Format(
237 PyExc_ValueError,
237 PyExc_ValueError,
238 "Manifest had implausibly-short line.");
238 "Manifest had implausibly-short line.");
239 break;
239 break;
240 default:
240 default:
241 PyErr_Format(PyExc_ValueError,
241 PyErr_Format(PyExc_ValueError,
242 "Unknown problem parsing manifest.");
242 "Unknown problem parsing manifest.");
243 }
243 }
244 return ret == 0 ? 0 : -1;
244 return ret == 0 ? 0 : -1;
245 }
245 }
246
246
247 static void lazymanifest_dealloc(lazymanifest *self)
247 static void lazymanifest_dealloc(lazymanifest *self)
248 {
248 {
249 /* free any extra lines we had to allocate */
249 /* free any extra lines we had to allocate */
250 int i;
250 int i;
251 for (i = 0; self->lines && (i < self->numlines); i++) {
251 for (i = 0; self->lines && (i < self->numlines); i++) {
252 if (self->lines[i].from_malloc) {
252 if (self->lines[i].from_malloc) {
253 free(self->lines[i].start);
253 free(self->lines[i].start);
254 }
254 }
255 }
255 }
256 free(self->lines);
256 free(self->lines);
257 self->lines = NULL;
257 self->lines = NULL;
258 if (self->pydata) {
258 if (self->pydata) {
259 Py_DECREF(self->pydata);
259 Py_DECREF(self->pydata);
260 self->pydata = NULL;
260 self->pydata = NULL;
261 }
261 }
262 PyObject_Del(self);
262 PyObject_Del(self);
263 }
263 }
264
264
265 /* iteration support */
265 /* iteration support */
266
266
267 typedef struct {
267 typedef struct {
268 PyObject_HEAD lazymanifest *m;
268 PyObject_HEAD lazymanifest *m;
269 Py_ssize_t pos;
269 Py_ssize_t pos;
270 } lmIter;
270 } lmIter;
271
271
272 static void lmiter_dealloc(PyObject *o)
272 static void lmiter_dealloc(PyObject *o)
273 {
273 {
274 lmIter *self = (lmIter *)o;
274 lmIter *self = (lmIter *)o;
275 Py_DECREF(self->m);
275 Py_DECREF(self->m);
276 PyObject_Del(self);
276 PyObject_Del(self);
277 }
277 }
278
278
279 static line *lmiter_nextline(lmIter *self)
279 static line *lmiter_nextline(lmIter *self)
280 {
280 {
281 do {
281 do {
282 self->pos++;
282 self->pos++;
283 if (self->pos >= self->m->numlines) {
283 if (self->pos >= self->m->numlines) {
284 return NULL;
284 return NULL;
285 }
285 }
286 /* skip over deleted manifest entries */
286 /* skip over deleted manifest entries */
287 } while (self->m->lines[self->pos].deleted);
287 } while (self->m->lines[self->pos].deleted);
288 return self->m->lines + self->pos;
288 return self->m->lines + self->pos;
289 }
289 }
290
290
291 static PyObject *lmiter_iterentriesnext(PyObject *o)
291 static PyObject *lmiter_iterentriesnext(PyObject *o)
292 {
292 {
293 lmIter *self = (lmIter *)o;
293 lmIter *self = (lmIter *)o;
294 Py_ssize_t pl;
294 Py_ssize_t pl;
295 line *l;
295 line *l;
296 char flag;
296 char flag;
297 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
297 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
298 l = lmiter_nextline(self);
298 l = lmiter_nextline(self);
299 if (!l) {
299 if (!l) {
300 goto done;
300 goto done;
301 }
301 }
302 pl = pathlen(l);
302 pl = pathlen(l);
303 path = PyBytes_FromStringAndSize(l->start, pl);
303 path = PyBytes_FromStringAndSize(l->start, pl);
304 hash = nodeof(self->m->nodelen, l, &flag);
304 hash = nodeof(self->m->nodelen, l, &flag);
305 if (!path || !hash) {
305 if (!path || !hash) {
306 goto done;
306 goto done;
307 }
307 }
308 flags = PyBytes_FromStringAndSize(&flag, flag ? 1 : 0);
308 flags = PyBytes_FromStringAndSize(&flag, flag ? 1 : 0);
309 if (!flags) {
309 if (!flags) {
310 goto done;
310 goto done;
311 }
311 }
312 ret = PyTuple_Pack(3, path, hash, flags);
312 ret = PyTuple_Pack(3, path, hash, flags);
313 done:
313 done:
314 Py_XDECREF(path);
314 Py_XDECREF(path);
315 Py_XDECREF(hash);
315 Py_XDECREF(hash);
316 Py_XDECREF(flags);
316 Py_XDECREF(flags);
317 return ret;
317 return ret;
318 }
318 }
319
319
320 #ifdef IS_PY3K
321 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
320 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
322 #else
323 #define LAZYMANIFESTENTRIESITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT \
324 | Py_TPFLAGS_HAVE_ITER
325 #endif
326
321
327 static PyTypeObject lazymanifestEntriesIterator = {
322 static PyTypeObject lazymanifestEntriesIterator = {
328 PyVarObject_HEAD_INIT(NULL, 0) /* header */
323 PyVarObject_HEAD_INIT(NULL, 0) /* header */
329 "parsers.lazymanifest.entriesiterator", /*tp_name */
324 "parsers.lazymanifest.entriesiterator", /*tp_name */
330 sizeof(lmIter), /*tp_basicsize */
325 sizeof(lmIter), /*tp_basicsize */
331 0, /*tp_itemsize */
326 0, /*tp_itemsize */
332 lmiter_dealloc, /*tp_dealloc */
327 lmiter_dealloc, /*tp_dealloc */
333 0, /*tp_print */
328 0, /*tp_print */
334 0, /*tp_getattr */
329 0, /*tp_getattr */
335 0, /*tp_setattr */
330 0, /*tp_setattr */
336 0, /*tp_compare */
331 0, /*tp_compare */
337 0, /*tp_repr */
332 0, /*tp_repr */
338 0, /*tp_as_number */
333 0, /*tp_as_number */
339 0, /*tp_as_sequence */
334 0, /*tp_as_sequence */
340 0, /*tp_as_mapping */
335 0, /*tp_as_mapping */
341 0, /*tp_hash */
336 0, /*tp_hash */
342 0, /*tp_call */
337 0, /*tp_call */
343 0, /*tp_str */
338 0, /*tp_str */
344 0, /*tp_getattro */
339 0, /*tp_getattro */
345 0, /*tp_setattro */
340 0, /*tp_setattro */
346 0, /*tp_as_buffer */
341 0, /*tp_as_buffer */
347 LAZYMANIFESTENTRIESITERATOR_TPFLAGS, /* tp_flags */
342 LAZYMANIFESTENTRIESITERATOR_TPFLAGS, /* tp_flags */
348 "Iterator for 3-tuples in a lazymanifest.", /* tp_doc */
343 "Iterator for 3-tuples in a lazymanifest.", /* tp_doc */
349 0, /* tp_traverse */
344 0, /* tp_traverse */
350 0, /* tp_clear */
345 0, /* tp_clear */
351 0, /* tp_richcompare */
346 0, /* tp_richcompare */
352 0, /* tp_weaklistoffset */
347 0, /* tp_weaklistoffset */
353 PyObject_SelfIter, /* tp_iter: __iter__() method */
348 PyObject_SelfIter, /* tp_iter: __iter__() method */
354 lmiter_iterentriesnext, /* tp_iternext: next() method */
349 lmiter_iterentriesnext, /* tp_iternext: next() method */
355 };
350 };
356
351
357 static PyObject *lmiter_iterkeysnext(PyObject *o)
352 static PyObject *lmiter_iterkeysnext(PyObject *o)
358 {
353 {
359 Py_ssize_t pl;
354 Py_ssize_t pl;
360 line *l = lmiter_nextline((lmIter *)o);
355 line *l = lmiter_nextline((lmIter *)o);
361 if (!l) {
356 if (!l) {
362 return NULL;
357 return NULL;
363 }
358 }
364 pl = pathlen(l);
359 pl = pathlen(l);
365 return PyBytes_FromStringAndSize(l->start, pl);
360 return PyBytes_FromStringAndSize(l->start, pl);
366 }
361 }
367
362
368 #ifdef IS_PY3K
369 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
363 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT
370 #else
371 #define LAZYMANIFESTKEYSITERATOR_TPFLAGS Py_TPFLAGS_DEFAULT \
372 | Py_TPFLAGS_HAVE_ITER
373 #endif
374
364
375 static PyTypeObject lazymanifestKeysIterator = {
365 static PyTypeObject lazymanifestKeysIterator = {
376 PyVarObject_HEAD_INIT(NULL, 0) /* header */
366 PyVarObject_HEAD_INIT(NULL, 0) /* header */
377 "parsers.lazymanifest.keysiterator", /*tp_name */
367 "parsers.lazymanifest.keysiterator", /*tp_name */
378 sizeof(lmIter), /*tp_basicsize */
368 sizeof(lmIter), /*tp_basicsize */
379 0, /*tp_itemsize */
369 0, /*tp_itemsize */
380 lmiter_dealloc, /*tp_dealloc */
370 lmiter_dealloc, /*tp_dealloc */
381 0, /*tp_print */
371 0, /*tp_print */
382 0, /*tp_getattr */
372 0, /*tp_getattr */
383 0, /*tp_setattr */
373 0, /*tp_setattr */
384 0, /*tp_compare */
374 0, /*tp_compare */
385 0, /*tp_repr */
375 0, /*tp_repr */
386 0, /*tp_as_number */
376 0, /*tp_as_number */
387 0, /*tp_as_sequence */
377 0, /*tp_as_sequence */
388 0, /*tp_as_mapping */
378 0, /*tp_as_mapping */
389 0, /*tp_hash */
379 0, /*tp_hash */
390 0, /*tp_call */
380 0, /*tp_call */
391 0, /*tp_str */
381 0, /*tp_str */
392 0, /*tp_getattro */
382 0, /*tp_getattro */
393 0, /*tp_setattro */
383 0, /*tp_setattro */
394 0, /*tp_as_buffer */
384 0, /*tp_as_buffer */
395 LAZYMANIFESTKEYSITERATOR_TPFLAGS, /* tp_flags */
385 LAZYMANIFESTKEYSITERATOR_TPFLAGS, /* tp_flags */
396 "Keys iterator for a lazymanifest.", /* tp_doc */
386 "Keys iterator for a lazymanifest.", /* tp_doc */
397 0, /* tp_traverse */
387 0, /* tp_traverse */
398 0, /* tp_clear */
388 0, /* tp_clear */
399 0, /* tp_richcompare */
389 0, /* tp_richcompare */
400 0, /* tp_weaklistoffset */
390 0, /* tp_weaklistoffset */
401 PyObject_SelfIter, /* tp_iter: __iter__() method */
391 PyObject_SelfIter, /* tp_iter: __iter__() method */
402 lmiter_iterkeysnext, /* tp_iternext: next() method */
392 lmiter_iterkeysnext, /* tp_iternext: next() method */
403 };
393 };
404
394
405 static lazymanifest *lazymanifest_copy(lazymanifest *self);
395 static lazymanifest *lazymanifest_copy(lazymanifest *self);
406
396
407 static PyObject *lazymanifest_getentriesiter(lazymanifest *self)
397 static PyObject *lazymanifest_getentriesiter(lazymanifest *self)
408 {
398 {
409 lmIter *i = NULL;
399 lmIter *i = NULL;
410 lazymanifest *t = lazymanifest_copy(self);
400 lazymanifest *t = lazymanifest_copy(self);
411 if (!t) {
401 if (!t) {
412 PyErr_NoMemory();
402 PyErr_NoMemory();
413 return NULL;
403 return NULL;
414 }
404 }
415 i = PyObject_New(lmIter, &lazymanifestEntriesIterator);
405 i = PyObject_New(lmIter, &lazymanifestEntriesIterator);
416 if (i) {
406 if (i) {
417 i->m = t;
407 i->m = t;
418 i->pos = -1;
408 i->pos = -1;
419 } else {
409 } else {
420 Py_DECREF(t);
410 Py_DECREF(t);
421 PyErr_NoMemory();
411 PyErr_NoMemory();
422 }
412 }
423 return (PyObject *)i;
413 return (PyObject *)i;
424 }
414 }
425
415
426 static PyObject *lazymanifest_getkeysiter(lazymanifest *self)
416 static PyObject *lazymanifest_getkeysiter(lazymanifest *self)
427 {
417 {
428 lmIter *i = NULL;
418 lmIter *i = NULL;
429 lazymanifest *t = lazymanifest_copy(self);
419 lazymanifest *t = lazymanifest_copy(self);
430 if (!t) {
420 if (!t) {
431 PyErr_NoMemory();
421 PyErr_NoMemory();
432 return NULL;
422 return NULL;
433 }
423 }
434 i = PyObject_New(lmIter, &lazymanifestKeysIterator);
424 i = PyObject_New(lmIter, &lazymanifestKeysIterator);
435 if (i) {
425 if (i) {
436 i->m = t;
426 i->m = t;
437 i->pos = -1;
427 i->pos = -1;
438 } else {
428 } else {
439 Py_DECREF(t);
429 Py_DECREF(t);
440 PyErr_NoMemory();
430 PyErr_NoMemory();
441 }
431 }
442 return (PyObject *)i;
432 return (PyObject *)i;
443 }
433 }
444
434
445 /* __getitem__ and __setitem__ support */
435 /* __getitem__ and __setitem__ support */
446
436
447 static Py_ssize_t lazymanifest_size(lazymanifest *self)
437 static Py_ssize_t lazymanifest_size(lazymanifest *self)
448 {
438 {
449 return self->livelines;
439 return self->livelines;
450 }
440 }
451
441
452 static int linecmp(const void *left, const void *right)
442 static int linecmp(const void *left, const void *right)
453 {
443 {
454 return strcmp(((const line *)left)->start,
444 return strcmp(((const line *)left)->start,
455 ((const line *)right)->start);
445 ((const line *)right)->start);
456 }
446 }
457
447
458 static PyObject *lazymanifest_getitem(lazymanifest *self, PyObject *key)
448 static PyObject *lazymanifest_getitem(lazymanifest *self, PyObject *key)
459 {
449 {
460 line needle;
450 line needle;
461 line *hit;
451 line *hit;
462 if (!PyBytes_Check(key)) {
452 if (!PyBytes_Check(key)) {
463 PyErr_Format(PyExc_TypeError,
453 PyErr_Format(PyExc_TypeError,
464 "getitem: manifest keys must be a string.");
454 "getitem: manifest keys must be a string.");
465 return NULL;
455 return NULL;
466 }
456 }
467 needle.start = PyBytes_AsString(key);
457 needle.start = PyBytes_AsString(key);
468 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
458 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
469 &linecmp);
459 &linecmp);
470 if (!hit || hit->deleted) {
460 if (!hit || hit->deleted) {
471 PyErr_Format(PyExc_KeyError, "No such manifest entry.");
461 PyErr_Format(PyExc_KeyError, "No such manifest entry.");
472 return NULL;
462 return NULL;
473 }
463 }
474 return hashflags(self->nodelen, hit);
464 return hashflags(self->nodelen, hit);
475 }
465 }
476
466
477 static int lazymanifest_delitem(lazymanifest *self, PyObject *key)
467 static int lazymanifest_delitem(lazymanifest *self, PyObject *key)
478 {
468 {
479 line needle;
469 line needle;
480 line *hit;
470 line *hit;
481 if (!PyBytes_Check(key)) {
471 if (!PyBytes_Check(key)) {
482 PyErr_Format(PyExc_TypeError,
472 PyErr_Format(PyExc_TypeError,
483 "delitem: manifest keys must be a string.");
473 "delitem: manifest keys must be a string.");
484 return -1;
474 return -1;
485 }
475 }
486 needle.start = PyBytes_AsString(key);
476 needle.start = PyBytes_AsString(key);
487 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
477 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
488 &linecmp);
478 &linecmp);
489 if (!hit || hit->deleted) {
479 if (!hit || hit->deleted) {
490 PyErr_Format(PyExc_KeyError,
480 PyErr_Format(PyExc_KeyError,
491 "Tried to delete nonexistent manifest entry.");
481 "Tried to delete nonexistent manifest entry.");
492 return -1;
482 return -1;
493 }
483 }
494 self->dirty = true;
484 self->dirty = true;
495 hit->deleted = true;
485 hit->deleted = true;
496 self->livelines--;
486 self->livelines--;
497 return 0;
487 return 0;
498 }
488 }
499
489
500 /* Do a binary search for the insertion point for new, creating the
490 /* Do a binary search for the insertion point for new, creating the
501 * new entry if needed. */
491 * new entry if needed. */
502 static int internalsetitem(lazymanifest *self, line *new)
492 static int internalsetitem(lazymanifest *self, line *new)
503 {
493 {
504 int start = 0, end = self->numlines;
494 int start = 0, end = self->numlines;
505 while (start < end) {
495 while (start < end) {
506 int pos = start + (end - start) / 2;
496 int pos = start + (end - start) / 2;
507 int c = linecmp(new, self->lines + pos);
497 int c = linecmp(new, self->lines + pos);
508 if (c < 0)
498 if (c < 0)
509 end = pos;
499 end = pos;
510 else if (c > 0)
500 else if (c > 0)
511 start = pos + 1;
501 start = pos + 1;
512 else {
502 else {
513 if (self->lines[pos].deleted)
503 if (self->lines[pos].deleted)
514 self->livelines++;
504 self->livelines++;
515 if (self->lines[pos].from_malloc)
505 if (self->lines[pos].from_malloc)
516 free(self->lines[pos].start);
506 free(self->lines[pos].start);
517 start = pos;
507 start = pos;
518 goto finish;
508 goto finish;
519 }
509 }
520 }
510 }
521 /* being here means we need to do an insert */
511 /* being here means we need to do an insert */
522 if (!realloc_if_full(self)) {
512 if (!realloc_if_full(self)) {
523 PyErr_NoMemory();
513 PyErr_NoMemory();
524 return -1;
514 return -1;
525 }
515 }
526 memmove(self->lines + start + 1, self->lines + start,
516 memmove(self->lines + start + 1, self->lines + start,
527 (self->numlines - start) * sizeof(line));
517 (self->numlines - start) * sizeof(line));
528 self->numlines++;
518 self->numlines++;
529 self->livelines++;
519 self->livelines++;
530 finish:
520 finish:
531 self->lines[start] = *new;
521 self->lines[start] = *new;
532 self->dirty = true;
522 self->dirty = true;
533 return 0;
523 return 0;
534 }
524 }
535
525
536 static int lazymanifest_setitem(
526 static int lazymanifest_setitem(
537 lazymanifest *self, PyObject *key, PyObject *value)
527 lazymanifest *self, PyObject *key, PyObject *value)
538 {
528 {
539 char *path;
529 char *path;
540 Py_ssize_t plen;
530 Py_ssize_t plen;
541 PyObject *pyhash;
531 PyObject *pyhash;
542 Py_ssize_t hlen;
532 Py_ssize_t hlen;
543 char *hash;
533 char *hash;
544 PyObject *pyflags;
534 PyObject *pyflags;
545 char *flags;
535 char *flags;
546 Py_ssize_t flen;
536 Py_ssize_t flen;
547 Py_ssize_t dlen;
537 Py_ssize_t dlen;
548 char *dest;
538 char *dest;
549 int i;
539 int i;
550 line new;
540 line new;
551 if (!PyBytes_Check(key)) {
541 if (!PyBytes_Check(key)) {
552 PyErr_Format(PyExc_TypeError,
542 PyErr_Format(PyExc_TypeError,
553 "setitem: manifest keys must be a string.");
543 "setitem: manifest keys must be a string.");
554 return -1;
544 return -1;
555 }
545 }
556 if (!value) {
546 if (!value) {
557 return lazymanifest_delitem(self, key);
547 return lazymanifest_delitem(self, key);
558 }
548 }
559 if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) {
549 if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) {
560 PyErr_Format(PyExc_TypeError,
550 PyErr_Format(PyExc_TypeError,
561 "Manifest values must be a tuple of (node, flags).");
551 "Manifest values must be a tuple of (node, flags).");
562 return -1;
552 return -1;
563 }
553 }
564 if (PyBytes_AsStringAndSize(key, &path, &plen) == -1) {
554 if (PyBytes_AsStringAndSize(key, &path, &plen) == -1) {
565 return -1;
555 return -1;
566 }
556 }
567
557
568 pyhash = PyTuple_GetItem(value, 0);
558 pyhash = PyTuple_GetItem(value, 0);
569 if (!PyBytes_Check(pyhash)) {
559 if (!PyBytes_Check(pyhash)) {
570 PyErr_Format(PyExc_TypeError,
560 PyErr_Format(PyExc_TypeError,
571 "node must be a %zi bytes string", self->nodelen);
561 "node must be a %zi bytes string", self->nodelen);
572 return -1;
562 return -1;
573 }
563 }
574 hlen = PyBytes_Size(pyhash);
564 hlen = PyBytes_Size(pyhash);
575 if (hlen != self->nodelen) {
565 if (hlen != self->nodelen) {
576 PyErr_Format(PyExc_TypeError,
566 PyErr_Format(PyExc_TypeError,
577 "node must be a %zi bytes string", self->nodelen);
567 "node must be a %zi bytes string", self->nodelen);
578 return -1;
568 return -1;
579 }
569 }
580 hash = PyBytes_AsString(pyhash);
570 hash = PyBytes_AsString(pyhash);
581
571
582 pyflags = PyTuple_GetItem(value, 1);
572 pyflags = PyTuple_GetItem(value, 1);
583 if (!PyBytes_Check(pyflags) || PyBytes_Size(pyflags) > 1) {
573 if (!PyBytes_Check(pyflags) || PyBytes_Size(pyflags) > 1) {
584 PyErr_Format(PyExc_TypeError,
574 PyErr_Format(PyExc_TypeError,
585 "flags must a 0 or 1 bytes string");
575 "flags must a 0 or 1 bytes string");
586 return -1;
576 return -1;
587 }
577 }
588 if (PyBytes_AsStringAndSize(pyflags, &flags, &flen) == -1) {
578 if (PyBytes_AsStringAndSize(pyflags, &flags, &flen) == -1) {
589 return -1;
579 return -1;
590 }
580 }
591 if (flen == 1) {
581 if (flen == 1) {
592 switch (*flags) {
582 switch (*flags) {
593 case 'l':
583 case 'l':
594 case 't':
584 case 't':
595 case 'x':
585 case 'x':
596 break;
586 break;
597 default:
587 default:
598 PyErr_Format(PyExc_TypeError, "invalid manifest flag");
588 PyErr_Format(PyExc_TypeError, "invalid manifest flag");
599 return -1;
589 return -1;
600 }
590 }
601 }
591 }
602 /* one null byte and one newline */
592 /* one null byte and one newline */
603 dlen = plen + hlen * 2 + 1 + flen + 1;
593 dlen = plen + hlen * 2 + 1 + flen + 1;
604 dest = malloc(dlen);
594 dest = malloc(dlen);
605 if (!dest) {
595 if (!dest) {
606 PyErr_NoMemory();
596 PyErr_NoMemory();
607 return -1;
597 return -1;
608 }
598 }
609 memcpy(dest, path, plen + 1);
599 memcpy(dest, path, plen + 1);
610 for (i = 0; i < hlen; i++) {
600 for (i = 0; i < hlen; i++) {
611 /* Cast to unsigned, so it will not get sign-extended when promoted
601 /* Cast to unsigned, so it will not get sign-extended when promoted
612 * to int (as is done when passing to a variadic function)
602 * to int (as is done when passing to a variadic function)
613 */
603 */
614 sprintf(dest + plen + 1 + (i * 2), "%02x", (unsigned char)hash[i]);
604 sprintf(dest + plen + 1 + (i * 2), "%02x", (unsigned char)hash[i]);
615 }
605 }
616 memcpy(dest + plen + 2 * hlen + 1, flags, flen);
606 memcpy(dest + plen + 2 * hlen + 1, flags, flen);
617 dest[plen + 2 * hlen + 1 + flen] = '\n';
607 dest[plen + 2 * hlen + 1 + flen] = '\n';
618 new.start = dest;
608 new.start = dest;
619 new.len = dlen;
609 new.len = dlen;
620 new.hash_suffix = '\0';
610 new.hash_suffix = '\0';
621 if (hlen > 20) {
611 if (hlen > 20) {
622 new.hash_suffix = hash[20];
612 new.hash_suffix = hash[20];
623 }
613 }
624 new.from_malloc = true; /* is `start` a pointer we allocated? */
614 new.from_malloc = true; /* is `start` a pointer we allocated? */
625 new.deleted = false; /* is this entry deleted? */
615 new.deleted = false; /* is this entry deleted? */
626 if (internalsetitem(self, &new)) {
616 if (internalsetitem(self, &new)) {
627 return -1;
617 return -1;
628 }
618 }
629 return 0;
619 return 0;
630 }
620 }
631
621
632 static PyMappingMethods lazymanifest_mapping_methods = {
622 static PyMappingMethods lazymanifest_mapping_methods = {
633 (lenfunc)lazymanifest_size, /* mp_length */
623 (lenfunc)lazymanifest_size, /* mp_length */
634 (binaryfunc)lazymanifest_getitem, /* mp_subscript */
624 (binaryfunc)lazymanifest_getitem, /* mp_subscript */
635 (objobjargproc)lazymanifest_setitem, /* mp_ass_subscript */
625 (objobjargproc)lazymanifest_setitem, /* mp_ass_subscript */
636 };
626 };
637
627
638 /* sequence methods (important or __contains__ builds an iterator) */
628 /* sequence methods (important or __contains__ builds an iterator) */
639
629
640 static int lazymanifest_contains(lazymanifest *self, PyObject *key)
630 static int lazymanifest_contains(lazymanifest *self, PyObject *key)
641 {
631 {
642 line needle;
632 line needle;
643 line *hit;
633 line *hit;
644 if (!PyBytes_Check(key)) {
634 if (!PyBytes_Check(key)) {
645 /* Our keys are always strings, so if the contains
635 /* Our keys are always strings, so if the contains
646 * check is for a non-string, just return false. */
636 * check is for a non-string, just return false. */
647 return 0;
637 return 0;
648 }
638 }
649 needle.start = PyBytes_AsString(key);
639 needle.start = PyBytes_AsString(key);
650 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
640 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
651 &linecmp);
641 &linecmp);
652 if (!hit || hit->deleted) {
642 if (!hit || hit->deleted) {
653 return 0;
643 return 0;
654 }
644 }
655 return 1;
645 return 1;
656 }
646 }
657
647
658 static PySequenceMethods lazymanifest_seq_meths = {
648 static PySequenceMethods lazymanifest_seq_meths = {
659 (lenfunc)lazymanifest_size, /* sq_length */
649 (lenfunc)lazymanifest_size, /* sq_length */
660 0, /* sq_concat */
650 0, /* sq_concat */
661 0, /* sq_repeat */
651 0, /* sq_repeat */
662 0, /* sq_item */
652 0, /* sq_item */
663 0, /* sq_slice */
653 0, /* sq_slice */
664 0, /* sq_ass_item */
654 0, /* sq_ass_item */
665 0, /* sq_ass_slice */
655 0, /* sq_ass_slice */
666 (objobjproc)lazymanifest_contains, /* sq_contains */
656 (objobjproc)lazymanifest_contains, /* sq_contains */
667 0, /* sq_inplace_concat */
657 0, /* sq_inplace_concat */
668 0, /* sq_inplace_repeat */
658 0, /* sq_inplace_repeat */
669 };
659 };
670
660
671
661
672 /* Other methods (copy, diff, etc) */
662 /* Other methods (copy, diff, etc) */
673 static PyTypeObject lazymanifestType;
663 static PyTypeObject lazymanifestType;
674
664
675 /* If the manifest has changes, build the new manifest text and reindex it. */
665 /* If the manifest has changes, build the new manifest text and reindex it. */
676 static int compact(lazymanifest *self)
666 static int compact(lazymanifest *self)
677 {
667 {
678 int i;
668 int i;
679 ssize_t need = 0;
669 ssize_t need = 0;
680 char *data;
670 char *data;
681 line *src, *dst;
671 line *src, *dst;
682 PyObject *pydata;
672 PyObject *pydata;
683 if (!self->dirty)
673 if (!self->dirty)
684 return 0;
674 return 0;
685 for (i = 0; i < self->numlines; i++) {
675 for (i = 0; i < self->numlines; i++) {
686 if (!self->lines[i].deleted) {
676 if (!self->lines[i].deleted) {
687 need += self->lines[i].len;
677 need += self->lines[i].len;
688 }
678 }
689 }
679 }
690 pydata = PyBytes_FromStringAndSize(NULL, need);
680 pydata = PyBytes_FromStringAndSize(NULL, need);
691 if (!pydata)
681 if (!pydata)
692 return -1;
682 return -1;
693 data = PyBytes_AsString(pydata);
683 data = PyBytes_AsString(pydata);
694 if (!data) {
684 if (!data) {
695 return -1;
685 return -1;
696 }
686 }
697 src = self->lines;
687 src = self->lines;
698 dst = self->lines;
688 dst = self->lines;
699 for (i = 0; i < self->numlines; i++, src++) {
689 for (i = 0; i < self->numlines; i++, src++) {
700 char *tofree = NULL;
690 char *tofree = NULL;
701 if (src->from_malloc) {
691 if (src->from_malloc) {
702 tofree = src->start;
692 tofree = src->start;
703 }
693 }
704 if (!src->deleted) {
694 if (!src->deleted) {
705 memcpy(data, src->start, src->len);
695 memcpy(data, src->start, src->len);
706 *dst = *src;
696 *dst = *src;
707 dst->start = data;
697 dst->start = data;
708 dst->from_malloc = false;
698 dst->from_malloc = false;
709 data += dst->len;
699 data += dst->len;
710 dst++;
700 dst++;
711 }
701 }
712 free(tofree);
702 free(tofree);
713 }
703 }
714 Py_DECREF(self->pydata);
704 Py_DECREF(self->pydata);
715 self->pydata = pydata;
705 self->pydata = pydata;
716 self->numlines = self->livelines;
706 self->numlines = self->livelines;
717 self->dirty = false;
707 self->dirty = false;
718 return 0;
708 return 0;
719 }
709 }
720
710
721 static PyObject *lazymanifest_text(lazymanifest *self)
711 static PyObject *lazymanifest_text(lazymanifest *self)
722 {
712 {
723 if (compact(self) != 0) {
713 if (compact(self) != 0) {
724 PyErr_NoMemory();
714 PyErr_NoMemory();
725 return NULL;
715 return NULL;
726 }
716 }
727 Py_INCREF(self->pydata);
717 Py_INCREF(self->pydata);
728 return self->pydata;
718 return self->pydata;
729 }
719 }
730
720
731 static lazymanifest *lazymanifest_copy(lazymanifest *self)
721 static lazymanifest *lazymanifest_copy(lazymanifest *self)
732 {
722 {
733 lazymanifest *copy = NULL;
723 lazymanifest *copy = NULL;
734 if (compact(self) != 0) {
724 if (compact(self) != 0) {
735 goto nomem;
725 goto nomem;
736 }
726 }
737 copy = PyObject_New(lazymanifest, &lazymanifestType);
727 copy = PyObject_New(lazymanifest, &lazymanifestType);
738 if (!copy) {
728 if (!copy) {
739 goto nomem;
729 goto nomem;
740 }
730 }
741 lazymanifest_init_early(copy);
731 lazymanifest_init_early(copy);
742 copy->nodelen = self->nodelen;
732 copy->nodelen = self->nodelen;
743 copy->numlines = self->numlines;
733 copy->numlines = self->numlines;
744 copy->livelines = self->livelines;
734 copy->livelines = self->livelines;
745 copy->dirty = false;
735 copy->dirty = false;
746 copy->lines = malloc(self->maxlines *sizeof(line));
736 copy->lines = malloc(self->maxlines *sizeof(line));
747 if (!copy->lines) {
737 if (!copy->lines) {
748 goto nomem;
738 goto nomem;
749 }
739 }
750 memcpy(copy->lines, self->lines, self->numlines * sizeof(line));
740 memcpy(copy->lines, self->lines, self->numlines * sizeof(line));
751 copy->maxlines = self->maxlines;
741 copy->maxlines = self->maxlines;
752 copy->pydata = self->pydata;
742 copy->pydata = self->pydata;
753 Py_INCREF(copy->pydata);
743 Py_INCREF(copy->pydata);
754 return copy;
744 return copy;
755 nomem:
745 nomem:
756 PyErr_NoMemory();
746 PyErr_NoMemory();
757 Py_XDECREF(copy);
747 Py_XDECREF(copy);
758 return NULL;
748 return NULL;
759 }
749 }
760
750
761 static lazymanifest *lazymanifest_filtercopy(
751 static lazymanifest *lazymanifest_filtercopy(
762 lazymanifest *self, PyObject *matchfn)
752 lazymanifest *self, PyObject *matchfn)
763 {
753 {
764 lazymanifest *copy = NULL;
754 lazymanifest *copy = NULL;
765 int i;
755 int i;
766 if (!PyCallable_Check(matchfn)) {
756 if (!PyCallable_Check(matchfn)) {
767 PyErr_SetString(PyExc_TypeError, "matchfn must be callable");
757 PyErr_SetString(PyExc_TypeError, "matchfn must be callable");
768 return NULL;
758 return NULL;
769 }
759 }
770 /* compact ourselves first to avoid double-frees later when we
760 /* compact ourselves first to avoid double-frees later when we
771 * compact tmp so that it doesn't have random pointers to our
761 * compact tmp so that it doesn't have random pointers to our
772 * underlying from_malloc-data (self->pydata is safe) */
762 * underlying from_malloc-data (self->pydata is safe) */
773 if (compact(self) != 0) {
763 if (compact(self) != 0) {
774 goto nomem;
764 goto nomem;
775 }
765 }
776 copy = PyObject_New(lazymanifest, &lazymanifestType);
766 copy = PyObject_New(lazymanifest, &lazymanifestType);
777 if (!copy) {
767 if (!copy) {
778 goto nomem;
768 goto nomem;
779 }
769 }
780 lazymanifest_init_early(copy);
770 lazymanifest_init_early(copy);
781 copy->nodelen = self->nodelen;
771 copy->nodelen = self->nodelen;
782 copy->dirty = true;
772 copy->dirty = true;
783 copy->lines = malloc(self->maxlines * sizeof(line));
773 copy->lines = malloc(self->maxlines * sizeof(line));
784 if (!copy->lines) {
774 if (!copy->lines) {
785 goto nomem;
775 goto nomem;
786 }
776 }
787 copy->maxlines = self->maxlines;
777 copy->maxlines = self->maxlines;
788 copy->numlines = 0;
778 copy->numlines = 0;
789 copy->pydata = self->pydata;
779 copy->pydata = self->pydata;
790 Py_INCREF(copy->pydata);
780 Py_INCREF(copy->pydata);
791 for (i = 0; i < self->numlines; i++) {
781 for (i = 0; i < self->numlines; i++) {
792 PyObject *arglist = NULL, *result = NULL;
782 PyObject *arglist = NULL, *result = NULL;
793 arglist = Py_BuildValue(PY23("(s)", "(y)"),
783 arglist = Py_BuildValue(PY23("(s)", "(y)"),
794 self->lines[i].start);
784 self->lines[i].start);
795 if (!arglist) {
785 if (!arglist) {
796 goto bail;
786 goto bail;
797 }
787 }
798 result = PyObject_CallObject(matchfn, arglist);
788 result = PyObject_CallObject(matchfn, arglist);
799 Py_DECREF(arglist);
789 Py_DECREF(arglist);
800 /* if the callback raised an exception, just let it
790 /* if the callback raised an exception, just let it
801 * through and give up */
791 * through and give up */
802 if (!result) {
792 if (!result) {
803 goto bail;
793 goto bail;
804 }
794 }
805 if (PyObject_IsTrue(result)) {
795 if (PyObject_IsTrue(result)) {
806 assert(!(self->lines[i].from_malloc));
796 assert(!(self->lines[i].from_malloc));
807 copy->lines[copy->numlines++] = self->lines[i];
797 copy->lines[copy->numlines++] = self->lines[i];
808 }
798 }
809 Py_DECREF(result);
799 Py_DECREF(result);
810 }
800 }
811 copy->livelines = copy->numlines;
801 copy->livelines = copy->numlines;
812 return copy;
802 return copy;
813 nomem:
803 nomem:
814 PyErr_NoMemory();
804 PyErr_NoMemory();
815 bail:
805 bail:
816 Py_XDECREF(copy);
806 Py_XDECREF(copy);
817 return NULL;
807 return NULL;
818 }
808 }
819
809
820 static PyObject *lazymanifest_diff(lazymanifest *self, PyObject *args)
810 static PyObject *lazymanifest_diff(lazymanifest *self, PyObject *args)
821 {
811 {
822 lazymanifest *other;
812 lazymanifest *other;
823 PyObject *pyclean = NULL;
813 PyObject *pyclean = NULL;
824 bool listclean;
814 bool listclean;
825 PyObject *emptyTup = NULL, *ret = NULL;
815 PyObject *emptyTup = NULL, *ret = NULL;
826 PyObject *es;
816 PyObject *es;
827 int sneedle = 0, oneedle = 0;
817 int sneedle = 0, oneedle = 0;
828 if (!PyArg_ParseTuple(args, "O!|O", &lazymanifestType, &other, &pyclean)) {
818 if (!PyArg_ParseTuple(args, "O!|O", &lazymanifestType, &other, &pyclean)) {
829 return NULL;
819 return NULL;
830 }
820 }
831 listclean = (!pyclean) ? false : PyObject_IsTrue(pyclean);
821 listclean = (!pyclean) ? false : PyObject_IsTrue(pyclean);
832 es = PyBytes_FromString("");
822 es = PyBytes_FromString("");
833 if (!es) {
823 if (!es) {
834 goto nomem;
824 goto nomem;
835 }
825 }
836 emptyTup = PyTuple_Pack(2, Py_None, es);
826 emptyTup = PyTuple_Pack(2, Py_None, es);
837 Py_DECREF(es);
827 Py_DECREF(es);
838 if (!emptyTup) {
828 if (!emptyTup) {
839 goto nomem;
829 goto nomem;
840 }
830 }
841 ret = PyDict_New();
831 ret = PyDict_New();
842 if (!ret) {
832 if (!ret) {
843 goto nomem;
833 goto nomem;
844 }
834 }
845 while (sneedle != self->numlines || oneedle != other->numlines) {
835 while (sneedle != self->numlines || oneedle != other->numlines) {
846 line *left = self->lines + sneedle;
836 line *left = self->lines + sneedle;
847 line *right = other->lines + oneedle;
837 line *right = other->lines + oneedle;
848 int result;
838 int result;
849 PyObject *key;
839 PyObject *key;
850 PyObject *outer;
840 PyObject *outer;
851 /* If we're looking at a deleted entry and it's not
841 /* If we're looking at a deleted entry and it's not
852 * the end of the manifest, just skip it. */
842 * the end of the manifest, just skip it. */
853 if (sneedle < self->numlines && left->deleted) {
843 if (sneedle < self->numlines && left->deleted) {
854 sneedle++;
844 sneedle++;
855 continue;
845 continue;
856 }
846 }
857 if (oneedle < other->numlines && right->deleted) {
847 if (oneedle < other->numlines && right->deleted) {
858 oneedle++;
848 oneedle++;
859 continue;
849 continue;
860 }
850 }
861 /* if we're at the end of either manifest, then we
851 /* if we're at the end of either manifest, then we
862 * know the remaining items are adds so we can skip
852 * know the remaining items are adds so we can skip
863 * the strcmp. */
853 * the strcmp. */
864 if (sneedle == self->numlines) {
854 if (sneedle == self->numlines) {
865 result = 1;
855 result = 1;
866 } else if (oneedle == other->numlines) {
856 } else if (oneedle == other->numlines) {
867 result = -1;
857 result = -1;
868 } else {
858 } else {
869 result = linecmp(left, right);
859 result = linecmp(left, right);
870 }
860 }
871 key = result <= 0 ?
861 key = result <= 0 ?
872 PyBytes_FromString(left->start) :
862 PyBytes_FromString(left->start) :
873 PyBytes_FromString(right->start);
863 PyBytes_FromString(right->start);
874 if (!key)
864 if (!key)
875 goto nomem;
865 goto nomem;
876 if (result < 0) {
866 if (result < 0) {
877 PyObject *l = hashflags(self->nodelen, left);
867 PyObject *l = hashflags(self->nodelen, left);
878 if (!l) {
868 if (!l) {
879 goto nomem;
869 goto nomem;
880 }
870 }
881 outer = PyTuple_Pack(2, l, emptyTup);
871 outer = PyTuple_Pack(2, l, emptyTup);
882 Py_DECREF(l);
872 Py_DECREF(l);
883 if (!outer) {
873 if (!outer) {
884 goto nomem;
874 goto nomem;
885 }
875 }
886 PyDict_SetItem(ret, key, outer);
876 PyDict_SetItem(ret, key, outer);
887 Py_DECREF(outer);
877 Py_DECREF(outer);
888 sneedle++;
878 sneedle++;
889 } else if (result > 0) {
879 } else if (result > 0) {
890 PyObject *r = hashflags(self->nodelen, right);
880 PyObject *r = hashflags(self->nodelen, right);
891 if (!r) {
881 if (!r) {
892 goto nomem;
882 goto nomem;
893 }
883 }
894 outer = PyTuple_Pack(2, emptyTup, r);
884 outer = PyTuple_Pack(2, emptyTup, r);
895 Py_DECREF(r);
885 Py_DECREF(r);
896 if (!outer) {
886 if (!outer) {
897 goto nomem;
887 goto nomem;
898 }
888 }
899 PyDict_SetItem(ret, key, outer);
889 PyDict_SetItem(ret, key, outer);
900 Py_DECREF(outer);
890 Py_DECREF(outer);
901 oneedle++;
891 oneedle++;
902 } else {
892 } else {
903 /* file exists in both manifests */
893 /* file exists in both manifests */
904 if (left->len != right->len
894 if (left->len != right->len
905 || memcmp(left->start, right->start, left->len)
895 || memcmp(left->start, right->start, left->len)
906 || left->hash_suffix != right->hash_suffix) {
896 || left->hash_suffix != right->hash_suffix) {
907 PyObject *l = hashflags(self->nodelen, left);
897 PyObject *l = hashflags(self->nodelen, left);
908 PyObject *r;
898 PyObject *r;
909 if (!l) {
899 if (!l) {
910 goto nomem;
900 goto nomem;
911 }
901 }
912 r = hashflags(self->nodelen, right);
902 r = hashflags(self->nodelen, right);
913 if (!r) {
903 if (!r) {
914 Py_DECREF(l);
904 Py_DECREF(l);
915 goto nomem;
905 goto nomem;
916 }
906 }
917 outer = PyTuple_Pack(2, l, r);
907 outer = PyTuple_Pack(2, l, r);
918 Py_DECREF(l);
908 Py_DECREF(l);
919 Py_DECREF(r);
909 Py_DECREF(r);
920 if (!outer) {
910 if (!outer) {
921 goto nomem;
911 goto nomem;
922 }
912 }
923 PyDict_SetItem(ret, key, outer);
913 PyDict_SetItem(ret, key, outer);
924 Py_DECREF(outer);
914 Py_DECREF(outer);
925 } else if (listclean) {
915 } else if (listclean) {
926 PyDict_SetItem(ret, key, Py_None);
916 PyDict_SetItem(ret, key, Py_None);
927 }
917 }
928 sneedle++;
918 sneedle++;
929 oneedle++;
919 oneedle++;
930 }
920 }
931 Py_DECREF(key);
921 Py_DECREF(key);
932 }
922 }
933 Py_DECREF(emptyTup);
923 Py_DECREF(emptyTup);
934 return ret;
924 return ret;
935 nomem:
925 nomem:
936 PyErr_NoMemory();
926 PyErr_NoMemory();
937 Py_XDECREF(ret);
927 Py_XDECREF(ret);
938 Py_XDECREF(emptyTup);
928 Py_XDECREF(emptyTup);
939 return NULL;
929 return NULL;
940 }
930 }
941
931
942 static PyMethodDef lazymanifest_methods[] = {
932 static PyMethodDef lazymanifest_methods[] = {
943 {"iterkeys", (PyCFunction)lazymanifest_getkeysiter, METH_NOARGS,
933 {"iterkeys", (PyCFunction)lazymanifest_getkeysiter, METH_NOARGS,
944 "Iterate over file names in this lazymanifest."},
934 "Iterate over file names in this lazymanifest."},
945 {"iterentries", (PyCFunction)lazymanifest_getentriesiter, METH_NOARGS,
935 {"iterentries", (PyCFunction)lazymanifest_getentriesiter, METH_NOARGS,
946 "Iterate over (path, nodeid, flags) tuples in this lazymanifest."},
936 "Iterate over (path, nodeid, flags) tuples in this lazymanifest."},
947 {"copy", (PyCFunction)lazymanifest_copy, METH_NOARGS,
937 {"copy", (PyCFunction)lazymanifest_copy, METH_NOARGS,
948 "Make a copy of this lazymanifest."},
938 "Make a copy of this lazymanifest."},
949 {"filtercopy", (PyCFunction)lazymanifest_filtercopy, METH_O,
939 {"filtercopy", (PyCFunction)lazymanifest_filtercopy, METH_O,
950 "Make a copy of this manifest filtered by matchfn."},
940 "Make a copy of this manifest filtered by matchfn."},
951 {"diff", (PyCFunction)lazymanifest_diff, METH_VARARGS,
941 {"diff", (PyCFunction)lazymanifest_diff, METH_VARARGS,
952 "Compare this lazymanifest to another one."},
942 "Compare this lazymanifest to another one."},
953 {"text", (PyCFunction)lazymanifest_text, METH_NOARGS,
943 {"text", (PyCFunction)lazymanifest_text, METH_NOARGS,
954 "Encode this manifest to text."},
944 "Encode this manifest to text."},
955 {NULL},
945 {NULL},
956 };
946 };
957
947
958 #ifdef IS_PY3K
959 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT
948 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT
960 #else
961 #define LAZYMANIFEST_TPFLAGS Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_SEQUENCE_IN
962 #endif
963
949
964 static PyTypeObject lazymanifestType = {
950 static PyTypeObject lazymanifestType = {
965 PyVarObject_HEAD_INIT(NULL, 0) /* header */
951 PyVarObject_HEAD_INIT(NULL, 0) /* header */
966 "parsers.lazymanifest", /* tp_name */
952 "parsers.lazymanifest", /* tp_name */
967 sizeof(lazymanifest), /* tp_basicsize */
953 sizeof(lazymanifest), /* tp_basicsize */
968 0, /* tp_itemsize */
954 0, /* tp_itemsize */
969 (destructor)lazymanifest_dealloc, /* tp_dealloc */
955 (destructor)lazymanifest_dealloc, /* tp_dealloc */
970 0, /* tp_print */
956 0, /* tp_print */
971 0, /* tp_getattr */
957 0, /* tp_getattr */
972 0, /* tp_setattr */
958 0, /* tp_setattr */
973 0, /* tp_compare */
959 0, /* tp_compare */
974 0, /* tp_repr */
960 0, /* tp_repr */
975 0, /* tp_as_number */
961 0, /* tp_as_number */
976 &lazymanifest_seq_meths, /* tp_as_sequence */
962 &lazymanifest_seq_meths, /* tp_as_sequence */
977 &lazymanifest_mapping_methods, /* tp_as_mapping */
963 &lazymanifest_mapping_methods, /* tp_as_mapping */
978 0, /* tp_hash */
964 0, /* tp_hash */
979 0, /* tp_call */
965 0, /* tp_call */
980 0, /* tp_str */
966 0, /* tp_str */
981 0, /* tp_getattro */
967 0, /* tp_getattro */
982 0, /* tp_setattro */
968 0, /* tp_setattro */
983 0, /* tp_as_buffer */
969 0, /* tp_as_buffer */
984 LAZYMANIFEST_TPFLAGS, /* tp_flags */
970 LAZYMANIFEST_TPFLAGS, /* tp_flags */
985 "TODO(augie)", /* tp_doc */
971 "TODO(augie)", /* tp_doc */
986 0, /* tp_traverse */
972 0, /* tp_traverse */
987 0, /* tp_clear */
973 0, /* tp_clear */
988 0, /* tp_richcompare */
974 0, /* tp_richcompare */
989 0, /* tp_weaklistoffset */
975 0, /* tp_weaklistoffset */
990 (getiterfunc)lazymanifest_getkeysiter, /* tp_iter */
976 (getiterfunc)lazymanifest_getkeysiter, /* tp_iter */
991 0, /* tp_iternext */
977 0, /* tp_iternext */
992 lazymanifest_methods, /* tp_methods */
978 lazymanifest_methods, /* tp_methods */
993 0, /* tp_members */
979 0, /* tp_members */
994 0, /* tp_getset */
980 0, /* tp_getset */
995 0, /* tp_base */
981 0, /* tp_base */
996 0, /* tp_dict */
982 0, /* tp_dict */
997 0, /* tp_descr_get */
983 0, /* tp_descr_get */
998 0, /* tp_descr_set */
984 0, /* tp_descr_set */
999 0, /* tp_dictoffset */
985 0, /* tp_dictoffset */
1000 (initproc)lazymanifest_init, /* tp_init */
986 (initproc)lazymanifest_init, /* tp_init */
1001 0, /* tp_alloc */
987 0, /* tp_alloc */
1002 };
988 };
1003
989
1004 void manifest_module_init(PyObject * mod)
990 void manifest_module_init(PyObject * mod)
1005 {
991 {
1006 lazymanifestType.tp_new = PyType_GenericNew;
992 lazymanifestType.tp_new = PyType_GenericNew;
1007 if (PyType_Ready(&lazymanifestType) < 0)
993 if (PyType_Ready(&lazymanifestType) < 0)
1008 return;
994 return;
1009 Py_INCREF(&lazymanifestType);
995 Py_INCREF(&lazymanifestType);
1010
996
1011 PyModule_AddObject(mod, "lazymanifest",
997 PyModule_AddObject(mod, "lazymanifest",
1012 (PyObject *)&lazymanifestType);
998 (PyObject *)&lazymanifestType);
1013 }
999 }
General Comments 0
You need to be logged in to leave comments. Login now