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