##// END OF EJS Templates
lazymanifest: extract function for iterating to next line...
Martin von Zweigbergk -
r24294:3d485727 default
parent child Browse files
Show More
@@ -1,852 +1,859 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 <assert.h>
9 #include <assert.h>
10 #include <string.h>
10 #include <string.h>
11 #include <stdlib.h>
11 #include <stdlib.h>
12
12
13 #include <Python.h>
13 #include <Python.h>
14
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)
226 {
227 do {
228 self->pos++;
229 if (self->pos >= self->m->numlines) {
230 return NULL;
231 }
232 /* skip over deleted manifest entries */
233 } while (self->m->lines[self->pos].deleted);
234 return self->m->lines + self->pos;
235 }
236
225 static PyObject *lmiter_iternext(PyObject *o)
237 static PyObject *lmiter_iternext(PyObject *o)
226 {
238 {
227 size_t pl;
239 size_t pl;
228 line *l;
240 line *l;
229 Py_ssize_t consumed;
241 Py_ssize_t consumed;
230 PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
242 PyObject *path = NULL, *hash = NULL, *flags = NULL;
231 lmIter *self = (lmIter *)o;
243 l = lmiter_nextline((lmIter *)o);
232 do {
244 if (!l) {
233 self->pos++;
245 goto bail;
234 if (self->pos >= self->m->numlines) {
246 }
235 goto bail;
236 }
237 /* skip over deleted manifest entries */
238 } while (self->m->lines[self->pos].deleted);
239 l = self->m->lines + self->pos;
240 pl = pathlen(l);
247 pl = pathlen(l);
241 path = PyString_FromStringAndSize(l->start, pl);
248 path = PyString_FromStringAndSize(l->start, pl);
242 hash = nodeof(l);
249 hash = nodeof(l);
243 consumed = pl + 41;
250 consumed = pl + 41;
244 flags = PyString_FromStringAndSize(l->start + consumed,
251 flags = PyString_FromStringAndSize(l->start + consumed,
245 l->len - consumed - 1);
252 l->len - consumed - 1);
246 if (!path || !hash || !flags) {
253 if (!path || !hash || !flags) {
247 goto bail;
254 goto bail;
248 }
255 }
249 ret = PyTuple_Pack(3, path, hash, flags);
256 return PyTuple_Pack(3, path, hash, flags);
250 bail:
257 bail:
251 Py_XDECREF(path);
258 Py_XDECREF(path);
252 Py_XDECREF(hash);
259 Py_XDECREF(hash);
253 Py_XDECREF(flags);
260 Py_XDECREF(flags);
254 return ret;
261 return NULL;
255 }
262 }
256
263
257 static PyTypeObject lazymanifestIterator = {
264 static PyTypeObject lazymanifestIterator = {
258 PyObject_HEAD_INIT(NULL)
265 PyObject_HEAD_INIT(NULL)
259 0, /*ob_size */
266 0, /*ob_size */
260 "parsers.lazymanifest.iterator", /*tp_name */
267 "parsers.lazymanifest.iterator", /*tp_name */
261 sizeof(lmIter), /*tp_basicsize */
268 sizeof(lmIter), /*tp_basicsize */
262 0, /*tp_itemsize */
269 0, /*tp_itemsize */
263 lmiter_dealloc, /*tp_dealloc */
270 lmiter_dealloc, /*tp_dealloc */
264 0, /*tp_print */
271 0, /*tp_print */
265 0, /*tp_getattr */
272 0, /*tp_getattr */
266 0, /*tp_setattr */
273 0, /*tp_setattr */
267 0, /*tp_compare */
274 0, /*tp_compare */
268 0, /*tp_repr */
275 0, /*tp_repr */
269 0, /*tp_as_number */
276 0, /*tp_as_number */
270 0, /*tp_as_sequence */
277 0, /*tp_as_sequence */
271 0, /*tp_as_mapping */
278 0, /*tp_as_mapping */
272 0, /*tp_hash */
279 0, /*tp_hash */
273 0, /*tp_call */
280 0, /*tp_call */
274 0, /*tp_str */
281 0, /*tp_str */
275 0, /*tp_getattro */
282 0, /*tp_getattro */
276 0, /*tp_setattro */
283 0, /*tp_setattro */
277 0, /*tp_as_buffer */
284 0, /*tp_as_buffer */
278 /* tp_flags: Py_TPFLAGS_HAVE_ITER tells python to
285 /* tp_flags: Py_TPFLAGS_HAVE_ITER tells python to
279 use tp_iter and tp_iternext fields. */
286 use tp_iter and tp_iternext fields. */
280 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER,
287 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER,
281 "Iterator for a lazymanifest.", /* tp_doc */
288 "Iterator for a lazymanifest.", /* tp_doc */
282 0, /* tp_traverse */
289 0, /* tp_traverse */
283 0, /* tp_clear */
290 0, /* tp_clear */
284 0, /* tp_richcompare */
291 0, /* tp_richcompare */
285 0, /* tp_weaklistoffset */
292 0, /* tp_weaklistoffset */
286 PyObject_SelfIter, /* tp_iter: __iter__() method */
293 PyObject_SelfIter, /* tp_iter: __iter__() method */
287 lmiter_iternext, /* tp_iternext: next() method */
294 lmiter_iternext, /* tp_iternext: next() method */
288 };
295 };
289
296
290 static lazymanifest *lazymanifest_copy(lazymanifest *self);
297 static lazymanifest *lazymanifest_copy(lazymanifest *self);
291
298
292 static PyObject *lazymanifest_getiter(lazymanifest *self)
299 static PyObject *lazymanifest_getiter(lazymanifest *self)
293 {
300 {
294 lmIter *i = NULL;
301 lmIter *i = NULL;
295 lazymanifest *t = lazymanifest_copy(self);
302 lazymanifest *t = lazymanifest_copy(self);
296 if (!t) {
303 if (!t) {
297 PyErr_NoMemory();
304 PyErr_NoMemory();
298 return NULL;
305 return NULL;
299 }
306 }
300 i = PyObject_New(lmIter, &lazymanifestIterator);
307 i = PyObject_New(lmIter, &lazymanifestIterator);
301 if (i) {
308 if (i) {
302 i->m = t;
309 i->m = t;
303 i->pos = -1;
310 i->pos = -1;
304 } else {
311 } else {
305 Py_DECREF(t);
312 Py_DECREF(t);
306 PyErr_NoMemory();
313 PyErr_NoMemory();
307 }
314 }
308 return (PyObject *)i;
315 return (PyObject *)i;
309 }
316 }
310
317
311 /* __getitem__ and __setitem__ support */
318 /* __getitem__ and __setitem__ support */
312
319
313 static Py_ssize_t lazymanifest_size(lazymanifest *self)
320 static Py_ssize_t lazymanifest_size(lazymanifest *self)
314 {
321 {
315 return self->livelines;
322 return self->livelines;
316 }
323 }
317
324
318 static int linecmp(const void *left, const void *right)
325 static int linecmp(const void *left, const void *right)
319 {
326 {
320 return strcmp(((const line *)left)->start,
327 return strcmp(((const line *)left)->start,
321 ((const line *)right)->start);
328 ((const line *)right)->start);
322 }
329 }
323
330
324 static PyObject *lazymanifest_getitem(lazymanifest *self, PyObject *key)
331 static PyObject *lazymanifest_getitem(lazymanifest *self, PyObject *key)
325 {
332 {
326 line needle;
333 line needle;
327 line *hit;
334 line *hit;
328 if (!PyString_Check(key)) {
335 if (!PyString_Check(key)) {
329 PyErr_Format(PyExc_TypeError,
336 PyErr_Format(PyExc_TypeError,
330 "getitem: manifest keys must be a string.");
337 "getitem: manifest keys must be a string.");
331 return NULL;
338 return NULL;
332 }
339 }
333 needle.start = PyString_AsString(key);
340 needle.start = PyString_AsString(key);
334 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
341 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
335 &linecmp);
342 &linecmp);
336 if (!hit || hit->deleted) {
343 if (!hit || hit->deleted) {
337 PyErr_Format(PyExc_KeyError, "No such manifest entry.");
344 PyErr_Format(PyExc_KeyError, "No such manifest entry.");
338 return NULL;
345 return NULL;
339 }
346 }
340 return hashflags(hit);
347 return hashflags(hit);
341 }
348 }
342
349
343 static int lazymanifest_delitem(lazymanifest *self, PyObject *key)
350 static int lazymanifest_delitem(lazymanifest *self, PyObject *key)
344 {
351 {
345 line needle;
352 line needle;
346 line *hit;
353 line *hit;
347 if (!PyString_Check(key)) {
354 if (!PyString_Check(key)) {
348 PyErr_Format(PyExc_TypeError,
355 PyErr_Format(PyExc_TypeError,
349 "delitem: manifest keys must be a string.");
356 "delitem: manifest keys must be a string.");
350 return -1;
357 return -1;
351 }
358 }
352 needle.start = PyString_AsString(key);
359 needle.start = PyString_AsString(key);
353 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
360 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
354 &linecmp);
361 &linecmp);
355 if (!hit || hit->deleted) {
362 if (!hit || hit->deleted) {
356 PyErr_Format(PyExc_KeyError,
363 PyErr_Format(PyExc_KeyError,
357 "Tried to delete nonexistent manifest entry.");
364 "Tried to delete nonexistent manifest entry.");
358 return -1;
365 return -1;
359 }
366 }
360 self->dirty = true;
367 self->dirty = true;
361 hit->deleted = true;
368 hit->deleted = true;
362 self->livelines--;
369 self->livelines--;
363 return 0;
370 return 0;
364 }
371 }
365
372
366 /* Do a binary search for the insertion point for new, creating the
373 /* Do a binary search for the insertion point for new, creating the
367 * new entry if needed. */
374 * new entry if needed. */
368 static int internalsetitem(lazymanifest *self, line *new) {
375 static int internalsetitem(lazymanifest *self, line *new) {
369 int start = 0, end = self->numlines;
376 int start = 0, end = self->numlines;
370 while (start < end) {
377 while (start < end) {
371 int pos = start + (end - start) / 2;
378 int pos = start + (end - start) / 2;
372 int c = linecmp(new, self->lines + pos);
379 int c = linecmp(new, self->lines + pos);
373 if (c < 0)
380 if (c < 0)
374 end = pos;
381 end = pos;
375 else if (c > 0)
382 else if (c > 0)
376 start = pos + 1;
383 start = pos + 1;
377 else {
384 else {
378 if (self->lines[pos].deleted)
385 if (self->lines[pos].deleted)
379 self->livelines++;
386 self->livelines++;
380 start = pos;
387 start = pos;
381 goto finish;
388 goto finish;
382 }
389 }
383 }
390 }
384 /* being here means we need to do an insert */
391 /* being here means we need to do an insert */
385 if (!realloc_if_full(self)) {
392 if (!realloc_if_full(self)) {
386 PyErr_NoMemory();
393 PyErr_NoMemory();
387 return -1;
394 return -1;
388 }
395 }
389 memmove(self->lines + start + 1, self->lines + start,
396 memmove(self->lines + start + 1, self->lines + start,
390 (self->numlines - start) * sizeof(line));
397 (self->numlines - start) * sizeof(line));
391 self->numlines++;
398 self->numlines++;
392 self->livelines++;
399 self->livelines++;
393 finish:
400 finish:
394 self->lines[start] = *new;
401 self->lines[start] = *new;
395 self->dirty = true;
402 self->dirty = true;
396 return 0;
403 return 0;
397 }
404 }
398
405
399 static int lazymanifest_setitem(
406 static int lazymanifest_setitem(
400 lazymanifest *self, PyObject *key, PyObject *value)
407 lazymanifest *self, PyObject *key, PyObject *value)
401 {
408 {
402 char *path;
409 char *path;
403 Py_ssize_t plen;
410 Py_ssize_t plen;
404 PyObject *pyhash;
411 PyObject *pyhash;
405 Py_ssize_t hlen;
412 Py_ssize_t hlen;
406 char *hash;
413 char *hash;
407 PyObject *pyflags;
414 PyObject *pyflags;
408 char *flags;
415 char *flags;
409 Py_ssize_t flen;
416 Py_ssize_t flen;
410 size_t dlen;
417 size_t dlen;
411 char *dest;
418 char *dest;
412 int i;
419 int i;
413 line new;
420 line new;
414 if (!PyString_Check(key)) {
421 if (!PyString_Check(key)) {
415 PyErr_Format(PyExc_TypeError,
422 PyErr_Format(PyExc_TypeError,
416 "setitem: manifest keys must be a string.");
423 "setitem: manifest keys must be a string.");
417 return -1;
424 return -1;
418 }
425 }
419 if (!value) {
426 if (!value) {
420 return lazymanifest_delitem(self, key);
427 return lazymanifest_delitem(self, key);
421 }
428 }
422 if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) {
429 if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) {
423 PyErr_Format(PyExc_TypeError,
430 PyErr_Format(PyExc_TypeError,
424 "Manifest values must be a tuple of (node, flags).");
431 "Manifest values must be a tuple of (node, flags).");
425 return -1;
432 return -1;
426 }
433 }
427 if (PyString_AsStringAndSize(key, &path, &plen) == -1) {
434 if (PyString_AsStringAndSize(key, &path, &plen) == -1) {
428 return -1;
435 return -1;
429 }
436 }
430
437
431 pyhash = PyTuple_GetItem(value, 0);
438 pyhash = PyTuple_GetItem(value, 0);
432 if (!PyString_Check(pyhash)) {
439 if (!PyString_Check(pyhash)) {
433 PyErr_Format(PyExc_TypeError,
440 PyErr_Format(PyExc_TypeError,
434 "node must be a 20-byte string");
441 "node must be a 20-byte string");
435 return -1;
442 return -1;
436 }
443 }
437 hlen = PyString_Size(pyhash);
444 hlen = PyString_Size(pyhash);
438 /* Some parts of the codebase try and set 21 or 22
445 /* Some parts of the codebase try and set 21 or 22
439 * byte "hash" values in order to perturb things for
446 * byte "hash" values in order to perturb things for
440 * status. We have to preserve at least the 21st
447 * status. We have to preserve at least the 21st
441 * byte. Sigh. If there's a 22nd byte, we drop it on
448 * byte. Sigh. If there's a 22nd byte, we drop it on
442 * the floor, which works fine.
449 * the floor, which works fine.
443 */
450 */
444 if (hlen != 20 && hlen != 21 && hlen != 22) {
451 if (hlen != 20 && hlen != 21 && hlen != 22) {
445 PyErr_Format(PyExc_TypeError,
452 PyErr_Format(PyExc_TypeError,
446 "node must be a 20-byte string");
453 "node must be a 20-byte string");
447 return -1;
454 return -1;
448 }
455 }
449 hash = PyString_AsString(pyhash);
456 hash = PyString_AsString(pyhash);
450
457
451 pyflags = PyTuple_GetItem(value, 1);
458 pyflags = PyTuple_GetItem(value, 1);
452 if (!PyString_Check(pyflags) || PyString_Size(pyflags) > 1) {
459 if (!PyString_Check(pyflags) || PyString_Size(pyflags) > 1) {
453 PyErr_Format(PyExc_TypeError,
460 PyErr_Format(PyExc_TypeError,
454 "flags must a 0 or 1 byte string");
461 "flags must a 0 or 1 byte string");
455 return -1;
462 return -1;
456 }
463 }
457 if (PyString_AsStringAndSize(pyflags, &flags, &flen) == -1) {
464 if (PyString_AsStringAndSize(pyflags, &flags, &flen) == -1) {
458 return -1;
465 return -1;
459 }
466 }
460 /* one null byte and one newline */
467 /* one null byte and one newline */
461 dlen = plen + 41 + flen + 1;
468 dlen = plen + 41 + flen + 1;
462 dest = malloc(dlen);
469 dest = malloc(dlen);
463 if (!dest) {
470 if (!dest) {
464 PyErr_NoMemory();
471 PyErr_NoMemory();
465 return -1;
472 return -1;
466 }
473 }
467 memcpy(dest, path, plen + 1);
474 memcpy(dest, path, plen + 1);
468 for (i = 0; i < 20; i++) {
475 for (i = 0; i < 20; i++) {
469 /* Cast to unsigned, so it will not get sign-extended when promoted
476 /* Cast to unsigned, so it will not get sign-extended when promoted
470 * to int (as is done when passing to a variadic function)
477 * to int (as is done when passing to a variadic function)
471 */
478 */
472 sprintf(dest + plen + 1 + (i * 2), "%02x", (unsigned char)hash[i]);
479 sprintf(dest + plen + 1 + (i * 2), "%02x", (unsigned char)hash[i]);
473 }
480 }
474 memcpy(dest + plen + 41, flags, flen);
481 memcpy(dest + plen + 41, flags, flen);
475 dest[plen + 41 + flen] = '\n';
482 dest[plen + 41 + flen] = '\n';
476 new.start = dest;
483 new.start = dest;
477 new.len = dlen;
484 new.len = dlen;
478 new.hash_suffix = '\0';
485 new.hash_suffix = '\0';
479 if (hlen > 20) {
486 if (hlen > 20) {
480 new.hash_suffix = hash[20];
487 new.hash_suffix = hash[20];
481 }
488 }
482 new.from_malloc = true; /* is `start` a pointer we allocated? */
489 new.from_malloc = true; /* is `start` a pointer we allocated? */
483 new.deleted = false; /* is this entry deleted? */
490 new.deleted = false; /* is this entry deleted? */
484 if (internalsetitem(self, &new)) {
491 if (internalsetitem(self, &new)) {
485 return -1;
492 return -1;
486 }
493 }
487 return 0;
494 return 0;
488 }
495 }
489
496
490 static PyMappingMethods lazymanifest_mapping_methods = {
497 static PyMappingMethods lazymanifest_mapping_methods = {
491 (lenfunc)lazymanifest_size, /* mp_length */
498 (lenfunc)lazymanifest_size, /* mp_length */
492 (binaryfunc)lazymanifest_getitem, /* mp_subscript */
499 (binaryfunc)lazymanifest_getitem, /* mp_subscript */
493 (objobjargproc)lazymanifest_setitem, /* mp_ass_subscript */
500 (objobjargproc)lazymanifest_setitem, /* mp_ass_subscript */
494 };
501 };
495
502
496 /* sequence methods (important or __contains__ builds an iterator */
503 /* sequence methods (important or __contains__ builds an iterator */
497
504
498 static int lazymanifest_contains(lazymanifest *self, PyObject *key)
505 static int lazymanifest_contains(lazymanifest *self, PyObject *key)
499 {
506 {
500 line needle;
507 line needle;
501 line *hit;
508 line *hit;
502 if (!PyString_Check(key)) {
509 if (!PyString_Check(key)) {
503 /* Our keys are always strings, so if the contains
510 /* Our keys are always strings, so if the contains
504 * check is for a non-string, just return false. */
511 * check is for a non-string, just return false. */
505 return 0;
512 return 0;
506 }
513 }
507 needle.start = PyString_AsString(key);
514 needle.start = PyString_AsString(key);
508 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
515 hit = bsearch(&needle, self->lines, self->numlines, sizeof(line),
509 &linecmp);
516 &linecmp);
510 if (!hit || hit->deleted) {
517 if (!hit || hit->deleted) {
511 return 0;
518 return 0;
512 }
519 }
513 return 1;
520 return 1;
514 }
521 }
515
522
516 static PySequenceMethods lazymanifest_seq_meths = {
523 static PySequenceMethods lazymanifest_seq_meths = {
517 (lenfunc)lazymanifest_size, /* sq_length */
524 (lenfunc)lazymanifest_size, /* sq_length */
518 0, /* sq_concat */
525 0, /* sq_concat */
519 0, /* sq_repeat */
526 0, /* sq_repeat */
520 0, /* sq_item */
527 0, /* sq_item */
521 0, /* sq_slice */
528 0, /* sq_slice */
522 0, /* sq_ass_item */
529 0, /* sq_ass_item */
523 0, /* sq_ass_slice */
530 0, /* sq_ass_slice */
524 (objobjproc)lazymanifest_contains, /* sq_contains */
531 (objobjproc)lazymanifest_contains, /* sq_contains */
525 0, /* sq_inplace_concat */
532 0, /* sq_inplace_concat */
526 0, /* sq_inplace_repeat */
533 0, /* sq_inplace_repeat */
527 };
534 };
528
535
529
536
530 /* Other methods (copy, diff, etc) */
537 /* Other methods (copy, diff, etc) */
531 static PyTypeObject lazymanifestType;
538 static PyTypeObject lazymanifestType;
532
539
533 /* If the manifest has changes, build the new manifest text and reindex it. */
540 /* If the manifest has changes, build the new manifest text and reindex it. */
534 static int compact(lazymanifest *self) {
541 static int compact(lazymanifest *self) {
535 int i;
542 int i;
536 ssize_t need = 0;
543 ssize_t need = 0;
537 char *data;
544 char *data;
538 line *src, *dst;
545 line *src, *dst;
539 PyObject *pydata;
546 PyObject *pydata;
540 if (!self->dirty)
547 if (!self->dirty)
541 return 0;
548 return 0;
542 for (i = 0; i < self->numlines; i++) {
549 for (i = 0; i < self->numlines; i++) {
543 if (!self->lines[i].deleted) {
550 if (!self->lines[i].deleted) {
544 need += self->lines[i].len;
551 need += self->lines[i].len;
545 }
552 }
546 }
553 }
547 pydata = PyString_FromStringAndSize(NULL, need);
554 pydata = PyString_FromStringAndSize(NULL, need);
548 if (!pydata)
555 if (!pydata)
549 return -1;
556 return -1;
550 data = PyString_AsString(pydata);
557 data = PyString_AsString(pydata);
551 if (!data) {
558 if (!data) {
552 return -1;
559 return -1;
553 }
560 }
554 src = self->lines;
561 src = self->lines;
555 dst = self->lines;
562 dst = self->lines;
556 for (i = 0; i < self->numlines; i++, src++) {
563 for (i = 0; i < self->numlines; i++, src++) {
557 char *tofree = NULL;
564 char *tofree = NULL;
558 if (src->from_malloc) {
565 if (src->from_malloc) {
559 tofree = src->start;
566 tofree = src->start;
560 }
567 }
561 if (!src->deleted) {
568 if (!src->deleted) {
562 memcpy(data, src->start, src->len);
569 memcpy(data, src->start, src->len);
563 *dst = *src;
570 *dst = *src;
564 dst->start = data;
571 dst->start = data;
565 dst->from_malloc = false;
572 dst->from_malloc = false;
566 data += dst->len;
573 data += dst->len;
567 dst++;
574 dst++;
568 }
575 }
569 free(tofree);
576 free(tofree);
570 }
577 }
571 Py_DECREF(self->pydata);
578 Py_DECREF(self->pydata);
572 self->pydata = pydata;
579 self->pydata = pydata;
573 self->numlines = self->livelines;
580 self->numlines = self->livelines;
574 self->dirty = false;
581 self->dirty = false;
575 return 0;
582 return 0;
576 }
583 }
577
584
578 static PyObject *lazymanifest_text(lazymanifest *self)
585 static PyObject *lazymanifest_text(lazymanifest *self)
579 {
586 {
580 if (compact(self) != 0) {
587 if (compact(self) != 0) {
581 PyErr_NoMemory();
588 PyErr_NoMemory();
582 return NULL;
589 return NULL;
583 }
590 }
584 Py_INCREF(self->pydata);
591 Py_INCREF(self->pydata);
585 return self->pydata;
592 return self->pydata;
586 }
593 }
587
594
588 static lazymanifest *lazymanifest_copy(lazymanifest *self)
595 static lazymanifest *lazymanifest_copy(lazymanifest *self)
589 {
596 {
590 lazymanifest *copy = NULL;
597 lazymanifest *copy = NULL;
591 if (compact(self) != 0) {
598 if (compact(self) != 0) {
592 goto nomem;
599 goto nomem;
593 }
600 }
594 copy = PyObject_New(lazymanifest, &lazymanifestType);
601 copy = PyObject_New(lazymanifest, &lazymanifestType);
595 if (!copy) {
602 if (!copy) {
596 goto nomem;
603 goto nomem;
597 }
604 }
598 copy->numlines = self->numlines;
605 copy->numlines = self->numlines;
599 copy->livelines = self->livelines;
606 copy->livelines = self->livelines;
600 copy->dirty = false;
607 copy->dirty = false;
601 copy->lines = malloc(self->maxlines *sizeof(line));
608 copy->lines = malloc(self->maxlines *sizeof(line));
602 if (!copy->lines) {
609 if (!copy->lines) {
603 goto nomem;
610 goto nomem;
604 }
611 }
605 memcpy(copy->lines, self->lines, self->numlines * sizeof(line));
612 memcpy(copy->lines, self->lines, self->numlines * sizeof(line));
606 copy->maxlines = self->maxlines;
613 copy->maxlines = self->maxlines;
607 copy->pydata = self->pydata;
614 copy->pydata = self->pydata;
608 Py_INCREF(copy->pydata);
615 Py_INCREF(copy->pydata);
609 return copy;
616 return copy;
610 nomem:
617 nomem:
611 PyErr_NoMemory();
618 PyErr_NoMemory();
612 Py_XDECREF(copy);
619 Py_XDECREF(copy);
613 return NULL;
620 return NULL;
614 }
621 }
615
622
616 static lazymanifest *lazymanifest_filtercopy(
623 static lazymanifest *lazymanifest_filtercopy(
617 lazymanifest *self, PyObject *matchfn)
624 lazymanifest *self, PyObject *matchfn)
618 {
625 {
619 lazymanifest *copy = NULL;
626 lazymanifest *copy = NULL;
620 int i;
627 int i;
621 if (!PyCallable_Check(matchfn)) {
628 if (!PyCallable_Check(matchfn)) {
622 PyErr_SetString(PyExc_TypeError, "matchfn must be callable");
629 PyErr_SetString(PyExc_TypeError, "matchfn must be callable");
623 return NULL;
630 return NULL;
624 }
631 }
625 /* compact ourselves first to avoid double-frees later when we
632 /* compact ourselves first to avoid double-frees later when we
626 * compact tmp so that it doesn't have random pointers to our
633 * compact tmp so that it doesn't have random pointers to our
627 * underlying from_malloc-data (self->pydata is safe) */
634 * underlying from_malloc-data (self->pydata is safe) */
628 if (compact(self) != 0) {
635 if (compact(self) != 0) {
629 goto nomem;
636 goto nomem;
630 }
637 }
631 copy = PyObject_New(lazymanifest, &lazymanifestType);
638 copy = PyObject_New(lazymanifest, &lazymanifestType);
632 copy->dirty = true;
639 copy->dirty = true;
633 copy->lines = malloc(self->maxlines * sizeof(line));
640 copy->lines = malloc(self->maxlines * sizeof(line));
634 if (!copy->lines) {
641 if (!copy->lines) {
635 goto nomem;
642 goto nomem;
636 }
643 }
637 copy->maxlines = self->maxlines;
644 copy->maxlines = self->maxlines;
638 copy->numlines = 0;
645 copy->numlines = 0;
639 copy->pydata = self->pydata;
646 copy->pydata = self->pydata;
640 Py_INCREF(self->pydata);
647 Py_INCREF(self->pydata);
641 for (i = 0; i < self->numlines; i++) {
648 for (i = 0; i < self->numlines; i++) {
642 PyObject *arg = PyString_FromString(self->lines[i].start);
649 PyObject *arg = PyString_FromString(self->lines[i].start);
643 PyObject *arglist = PyTuple_Pack(1, arg);
650 PyObject *arglist = PyTuple_Pack(1, arg);
644 PyObject *result = PyObject_CallObject(matchfn, arglist);
651 PyObject *result = PyObject_CallObject(matchfn, arglist);
645 Py_DECREF(arglist);
652 Py_DECREF(arglist);
646 Py_DECREF(arg);
653 Py_DECREF(arg);
647 /* if the callback raised an exception, just let it
654 /* if the callback raised an exception, just let it
648 * through and give up */
655 * through and give up */
649 if (!result) {
656 if (!result) {
650 free(copy->lines);
657 free(copy->lines);
651 Py_DECREF(self->pydata);
658 Py_DECREF(self->pydata);
652 return NULL;
659 return NULL;
653 }
660 }
654 if (PyObject_IsTrue(result)) {
661 if (PyObject_IsTrue(result)) {
655 assert(!(self->lines[i].from_malloc));
662 assert(!(self->lines[i].from_malloc));
656 copy->lines[copy->numlines++] = self->lines[i];
663 copy->lines[copy->numlines++] = self->lines[i];
657 }
664 }
658 Py_DECREF(result);
665 Py_DECREF(result);
659 }
666 }
660 copy->livelines = copy->numlines;
667 copy->livelines = copy->numlines;
661 return copy;
668 return copy;
662 nomem:
669 nomem:
663 PyErr_NoMemory();
670 PyErr_NoMemory();
664 Py_XDECREF(copy);
671 Py_XDECREF(copy);
665 return NULL;
672 return NULL;
666 }
673 }
667
674
668 static PyObject *lazymanifest_diff(lazymanifest *self, PyObject *args)
675 static PyObject *lazymanifest_diff(lazymanifest *self, PyObject *args)
669 {
676 {
670 lazymanifest *other;
677 lazymanifest *other;
671 PyObject *pyclean = NULL;
678 PyObject *pyclean = NULL;
672 bool listclean;
679 bool listclean;
673 PyObject *emptyTup = NULL, *ret = NULL;
680 PyObject *emptyTup = NULL, *ret = NULL;
674 PyObject *es;
681 PyObject *es;
675 int sneedle = 0, oneedle = 0;
682 int sneedle = 0, oneedle = 0;
676 if (!PyArg_ParseTuple(args, "O!|O", &lazymanifestType, &other, &pyclean)) {
683 if (!PyArg_ParseTuple(args, "O!|O", &lazymanifestType, &other, &pyclean)) {
677 return NULL;
684 return NULL;
678 }
685 }
679 listclean = (!pyclean) ? false : PyObject_IsTrue(pyclean);
686 listclean = (!pyclean) ? false : PyObject_IsTrue(pyclean);
680 es = PyString_FromString("");
687 es = PyString_FromString("");
681 if (!es) {
688 if (!es) {
682 goto nomem;
689 goto nomem;
683 }
690 }
684 emptyTup = PyTuple_Pack(2, Py_None, es);
691 emptyTup = PyTuple_Pack(2, Py_None, es);
685 Py_DECREF(es);
692 Py_DECREF(es);
686 if (!emptyTup) {
693 if (!emptyTup) {
687 goto nomem;
694 goto nomem;
688 }
695 }
689 ret = PyDict_New();
696 ret = PyDict_New();
690 if (!ret) {
697 if (!ret) {
691 goto nomem;
698 goto nomem;
692 }
699 }
693 while (sneedle != self->numlines || oneedle != other->numlines) {
700 while (sneedle != self->numlines || oneedle != other->numlines) {
694 line *left = self->lines + sneedle;
701 line *left = self->lines + sneedle;
695 line *right = other->lines + oneedle;
702 line *right = other->lines + oneedle;
696 int result;
703 int result;
697 PyObject *key;
704 PyObject *key;
698 PyObject *outer;
705 PyObject *outer;
699 /* If we're looking at a deleted entry and it's not
706 /* If we're looking at a deleted entry and it's not
700 * the end of the manifest, just skip it. */
707 * the end of the manifest, just skip it. */
701 if (left->deleted && sneedle < self->numlines) {
708 if (left->deleted && sneedle < self->numlines) {
702 sneedle++;
709 sneedle++;
703 continue;
710 continue;
704 }
711 }
705 if (right->deleted && oneedle < other->numlines) {
712 if (right->deleted && oneedle < other->numlines) {
706 oneedle++;
713 oneedle++;
707 continue;
714 continue;
708 }
715 }
709 /* if we're at the end of either manifest, then we
716 /* if we're at the end of either manifest, then we
710 * know the remaining items are adds so we can skip
717 * know the remaining items are adds so we can skip
711 * the strcmp. */
718 * the strcmp. */
712 if (sneedle == self->numlines) {
719 if (sneedle == self->numlines) {
713 result = 1;
720 result = 1;
714 } else if (oneedle == other->numlines) {
721 } else if (oneedle == other->numlines) {
715 result = -1;
722 result = -1;
716 } else {
723 } else {
717 result = linecmp(left, right);
724 result = linecmp(left, right);
718 }
725 }
719 key = result <= 0 ?
726 key = result <= 0 ?
720 PyString_FromString(left->start) :
727 PyString_FromString(left->start) :
721 PyString_FromString(right->start);
728 PyString_FromString(right->start);
722 if (!key)
729 if (!key)
723 goto nomem;
730 goto nomem;
724 if (result < 0) {
731 if (result < 0) {
725 PyObject *l = hashflags(left);
732 PyObject *l = hashflags(left);
726 if (!l) {
733 if (!l) {
727 goto nomem;
734 goto nomem;
728 }
735 }
729 outer = PyTuple_Pack(2, l, emptyTup);
736 outer = PyTuple_Pack(2, l, emptyTup);
730 Py_DECREF(l);
737 Py_DECREF(l);
731 if (!outer) {
738 if (!outer) {
732 goto nomem;
739 goto nomem;
733 }
740 }
734 PyDict_SetItem(ret, key, outer);
741 PyDict_SetItem(ret, key, outer);
735 Py_DECREF(outer);
742 Py_DECREF(outer);
736 sneedle++;
743 sneedle++;
737 } else if (result > 0) {
744 } else if (result > 0) {
738 PyObject *r = hashflags(right);
745 PyObject *r = hashflags(right);
739 if (!r) {
746 if (!r) {
740 goto nomem;
747 goto nomem;
741 }
748 }
742 outer = PyTuple_Pack(2, emptyTup, r);
749 outer = PyTuple_Pack(2, emptyTup, r);
743 Py_DECREF(r);
750 Py_DECREF(r);
744 if (!outer) {
751 if (!outer) {
745 goto nomem;
752 goto nomem;
746 }
753 }
747 PyDict_SetItem(ret, key, outer);
754 PyDict_SetItem(ret, key, outer);
748 Py_DECREF(outer);
755 Py_DECREF(outer);
749 oneedle++;
756 oneedle++;
750 } else {
757 } else {
751 /* file exists in both manifests */
758 /* file exists in both manifests */
752 if (left->len != right->len
759 if (left->len != right->len
753 || memcmp(left->start, right->start, left->len)
760 || memcmp(left->start, right->start, left->len)
754 || left->hash_suffix != right->hash_suffix) {
761 || left->hash_suffix != right->hash_suffix) {
755 PyObject *l = hashflags(left);
762 PyObject *l = hashflags(left);
756 PyObject *r;
763 PyObject *r;
757 if (!l) {
764 if (!l) {
758 goto nomem;
765 goto nomem;
759 }
766 }
760 r = hashflags(right);
767 r = hashflags(right);
761 if (!r) {
768 if (!r) {
762 Py_DECREF(l);
769 Py_DECREF(l);
763 goto nomem;
770 goto nomem;
764 }
771 }
765 outer = PyTuple_Pack(2, l, r);
772 outer = PyTuple_Pack(2, l, r);
766 Py_DECREF(l);
773 Py_DECREF(l);
767 Py_DECREF(r);
774 Py_DECREF(r);
768 if (!outer) {
775 if (!outer) {
769 goto nomem;
776 goto nomem;
770 }
777 }
771 PyDict_SetItem(ret, key, outer);
778 PyDict_SetItem(ret, key, outer);
772 Py_DECREF(outer);
779 Py_DECREF(outer);
773 } else if (listclean) {
780 } else if (listclean) {
774 PyDict_SetItem(ret, key, Py_None);
781 PyDict_SetItem(ret, key, Py_None);
775 }
782 }
776 sneedle++;
783 sneedle++;
777 oneedle++;
784 oneedle++;
778 }
785 }
779 Py_DECREF(key);
786 Py_DECREF(key);
780 }
787 }
781 Py_DECREF(emptyTup);
788 Py_DECREF(emptyTup);
782 return ret;
789 return ret;
783 nomem:
790 nomem:
784 PyErr_NoMemory();
791 PyErr_NoMemory();
785 Py_XDECREF(ret);
792 Py_XDECREF(ret);
786 Py_XDECREF(emptyTup);
793 Py_XDECREF(emptyTup);
787 return NULL;
794 return NULL;
788 }
795 }
789
796
790 static PyMethodDef lazymanifest_methods[] = {
797 static PyMethodDef lazymanifest_methods[] = {
791 {"copy", (PyCFunction)lazymanifest_copy, METH_NOARGS,
798 {"copy", (PyCFunction)lazymanifest_copy, METH_NOARGS,
792 "Make a copy of this lazymanifest."},
799 "Make a copy of this lazymanifest."},
793 {"filtercopy", (PyCFunction)lazymanifest_filtercopy, METH_O,
800 {"filtercopy", (PyCFunction)lazymanifest_filtercopy, METH_O,
794 "Make a copy of this manifest filtered by matchfn."},
801 "Make a copy of this manifest filtered by matchfn."},
795 {"diff", (PyCFunction)lazymanifest_diff, METH_VARARGS,
802 {"diff", (PyCFunction)lazymanifest_diff, METH_VARARGS,
796 "Compare this lazymanifest to another one."},
803 "Compare this lazymanifest to another one."},
797 {"text", (PyCFunction)lazymanifest_text, METH_NOARGS,
804 {"text", (PyCFunction)lazymanifest_text, METH_NOARGS,
798 "Encode this manifest to text."},
805 "Encode this manifest to text."},
799 {NULL},
806 {NULL},
800 };
807 };
801
808
802 static PyTypeObject lazymanifestType = {
809 static PyTypeObject lazymanifestType = {
803 PyObject_HEAD_INIT(NULL)
810 PyObject_HEAD_INIT(NULL)
804 0, /* ob_size */
811 0, /* ob_size */
805 "parsers.lazymanifest", /* tp_name */
812 "parsers.lazymanifest", /* tp_name */
806 sizeof(lazymanifest), /* tp_basicsize */
813 sizeof(lazymanifest), /* tp_basicsize */
807 0, /* tp_itemsize */
814 0, /* tp_itemsize */
808 (destructor)lazymanifest_dealloc, /* tp_dealloc */
815 (destructor)lazymanifest_dealloc, /* tp_dealloc */
809 0, /* tp_print */
816 0, /* tp_print */
810 0, /* tp_getattr */
817 0, /* tp_getattr */
811 0, /* tp_setattr */
818 0, /* tp_setattr */
812 0, /* tp_compare */
819 0, /* tp_compare */
813 0, /* tp_repr */
820 0, /* tp_repr */
814 0, /* tp_as_number */
821 0, /* tp_as_number */
815 &lazymanifest_seq_meths, /* tp_as_sequence */
822 &lazymanifest_seq_meths, /* tp_as_sequence */
816 &lazymanifest_mapping_methods, /* tp_as_mapping */
823 &lazymanifest_mapping_methods, /* tp_as_mapping */
817 0, /* tp_hash */
824 0, /* tp_hash */
818 0, /* tp_call */
825 0, /* tp_call */
819 0, /* tp_str */
826 0, /* tp_str */
820 0, /* tp_getattro */
827 0, /* tp_getattro */
821 0, /* tp_setattro */
828 0, /* tp_setattro */
822 0, /* tp_as_buffer */
829 0, /* tp_as_buffer */
823 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_SEQUENCE_IN, /* tp_flags */
830 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_SEQUENCE_IN, /* tp_flags */
824 "TODO(augie)", /* tp_doc */
831 "TODO(augie)", /* tp_doc */
825 0, /* tp_traverse */
832 0, /* tp_traverse */
826 0, /* tp_clear */
833 0, /* tp_clear */
827 0, /* tp_richcompare */
834 0, /* tp_richcompare */
828 0, /* tp_weaklistoffset */
835 0, /* tp_weaklistoffset */
829 (getiterfunc)lazymanifest_getiter, /* tp_iter */
836 (getiterfunc)lazymanifest_getiter, /* tp_iter */
830 0, /* tp_iternext */
837 0, /* tp_iternext */
831 lazymanifest_methods, /* tp_methods */
838 lazymanifest_methods, /* tp_methods */
832 0, /* tp_members */
839 0, /* tp_members */
833 0, /* tp_getset */
840 0, /* tp_getset */
834 0, /* tp_base */
841 0, /* tp_base */
835 0, /* tp_dict */
842 0, /* tp_dict */
836 0, /* tp_descr_get */
843 0, /* tp_descr_get */
837 0, /* tp_descr_set */
844 0, /* tp_descr_set */
838 0, /* tp_dictoffset */
845 0, /* tp_dictoffset */
839 (initproc)lazymanifest_init, /* tp_init */
846 (initproc)lazymanifest_init, /* tp_init */
840 0, /* tp_alloc */
847 0, /* tp_alloc */
841 };
848 };
842
849
843 void manifest_module_init(PyObject * mod)
850 void manifest_module_init(PyObject * mod)
844 {
851 {
845 lazymanifestType.tp_new = PyType_GenericNew;
852 lazymanifestType.tp_new = PyType_GenericNew;
846 if (PyType_Ready(&lazymanifestType) < 0)
853 if (PyType_Ready(&lazymanifestType) < 0)
847 return;
854 return;
848 Py_INCREF(&lazymanifestType);
855 Py_INCREF(&lazymanifestType);
849
856
850 PyModule_AddObject(mod, "lazymanifest",
857 PyModule_AddObject(mod, "lazymanifest",
851 (PyObject *)&lazymanifestType);
858 (PyObject *)&lazymanifestType);
852 }
859 }
General Comments 0
You need to be logged in to leave comments. Login now