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