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