##// END OF EJS Templates
parsers._asciilower: use an explicit return object...
Siddharth Agarwal -
r24575:a62e9574 default
parent child Browse files
Show More
@@ -1,2524 +1,2526
1 1 /*
2 2 parsers.c - efficient content parsing
3 3
4 4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
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
10 10 #include <Python.h>
11 11 #include <ctype.h>
12 12 #include <stddef.h>
13 13 #include <string.h>
14 14
15 15 #include "util.h"
16 16
17 17 static char *versionerrortext = "Python minor version mismatch";
18 18
19 19 static int8_t hextable[256] = {
20 20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23 23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
24 24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
25 25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26 26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
27 27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35 35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
36 36 };
37 37
38 38 static char lowertable[128] = {
39 39 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
40 40 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
41 41 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
42 42 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
43 43 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
44 44 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
45 45 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
46 46 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
47 47 '\x40',
48 48 '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', /* A-G */
49 49 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', /* H-O */
50 50 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', /* P-W */
51 51 '\x78', '\x79', '\x7a', /* X-Z */
52 52 '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
53 53 '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
54 54 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
55 55 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
56 56 '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
57 57 };
58 58
59 59 static inline int hexdigit(const char *p, Py_ssize_t off)
60 60 {
61 61 int8_t val = hextable[(unsigned char)p[off]];
62 62
63 63 if (val >= 0) {
64 64 return val;
65 65 }
66 66
67 67 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
68 68 return 0;
69 69 }
70 70
71 71 /*
72 72 * Turn a hex-encoded string into binary.
73 73 */
74 74 PyObject *unhexlify(const char *str, int len)
75 75 {
76 76 PyObject *ret;
77 77 char *d;
78 78 int i;
79 79
80 80 ret = PyBytes_FromStringAndSize(NULL, len / 2);
81 81
82 82 if (!ret)
83 83 return NULL;
84 84
85 85 d = PyBytes_AsString(ret);
86 86
87 87 for (i = 0; i < len;) {
88 88 int hi = hexdigit(str, i++);
89 89 int lo = hexdigit(str, i++);
90 90 *d++ = (hi << 4) | lo;
91 91 }
92 92
93 93 return ret;
94 94 }
95 95
96 96 static inline PyObject *_asciilower(PyObject *str_obj)
97 97 {
98 98 char *str, *newstr;
99 99 Py_ssize_t i, len;
100 100 PyObject *newobj = NULL;
101 PyObject *ret = NULL;
101 102
102 103 str = PyBytes_AS_STRING(str_obj);
103 104 len = PyBytes_GET_SIZE(str_obj);
104 105
105 106 newobj = PyBytes_FromStringAndSize(NULL, len);
106 107 if (!newobj)
107 108 goto quit;
108 109
109 110 newstr = PyBytes_AS_STRING(newobj);
110 111
111 112 for (i = 0; i < len; i++) {
112 113 char c = str[i];
113 114 if (c & 0x80) {
114 115 PyObject *err = PyUnicodeDecodeError_Create(
115 116 "ascii", str, len, i, (i + 1),
116 117 "unexpected code byte");
117 118 PyErr_SetObject(PyExc_UnicodeDecodeError, err);
118 119 Py_XDECREF(err);
119 120 goto quit;
120 121 }
121 122 newstr[i] = lowertable[(unsigned char)c];
122 123 }
123 124
124 return newobj;
125 ret = newobj;
126 Py_INCREF(ret);
125 127 quit:
126 128 Py_XDECREF(newobj);
127 return NULL;
129 return ret;
128 130 }
129 131
130 132 static PyObject *asciilower(PyObject *self, PyObject *args)
131 133 {
132 134 PyObject *str_obj;
133 135 if (!PyArg_ParseTuple(args, "O!:asciilower", &PyBytes_Type, &str_obj))
134 136 return NULL;
135 137 return _asciilower(str_obj);
136 138 }
137 139
138 140 /*
139 141 * This code assumes that a manifest is stitched together with newline
140 142 * ('\n') characters.
141 143 */
142 144 static PyObject *parse_manifest(PyObject *self, PyObject *args)
143 145 {
144 146 PyObject *mfdict, *fdict;
145 147 char *str, *start, *end;
146 148 int len;
147 149
148 150 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
149 151 &PyDict_Type, &mfdict,
150 152 &PyDict_Type, &fdict,
151 153 &str, &len))
152 154 goto quit;
153 155
154 156 start = str;
155 157 end = str + len;
156 158 while (start < end) {
157 159 PyObject *file = NULL, *node = NULL;
158 160 PyObject *flags = NULL;
159 161 char *zero = NULL, *newline = NULL;
160 162 ptrdiff_t nlen;
161 163
162 164 zero = memchr(start, '\0', end - start);
163 165 if (!zero) {
164 166 PyErr_SetString(PyExc_ValueError,
165 167 "manifest entry has no separator");
166 168 goto quit;
167 169 }
168 170
169 171 newline = memchr(zero + 1, '\n', end - (zero + 1));
170 172 if (!newline) {
171 173 PyErr_SetString(PyExc_ValueError,
172 174 "manifest contains trailing garbage");
173 175 goto quit;
174 176 }
175 177
176 178 file = PyBytes_FromStringAndSize(start, zero - start);
177 179
178 180 if (!file)
179 181 goto bail;
180 182
181 183 nlen = newline - zero - 1;
182 184
183 185 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
184 186 if (!node)
185 187 goto bail;
186 188
187 189 if (nlen > 40) {
188 190 flags = PyBytes_FromStringAndSize(zero + 41,
189 191 nlen - 40);
190 192 if (!flags)
191 193 goto bail;
192 194
193 195 if (PyDict_SetItem(fdict, file, flags) == -1)
194 196 goto bail;
195 197 }
196 198
197 199 if (PyDict_SetItem(mfdict, file, node) == -1)
198 200 goto bail;
199 201
200 202 start = newline + 1;
201 203
202 204 Py_XDECREF(flags);
203 205 Py_XDECREF(node);
204 206 Py_XDECREF(file);
205 207 continue;
206 208 bail:
207 209 Py_XDECREF(flags);
208 210 Py_XDECREF(node);
209 211 Py_XDECREF(file);
210 212 goto quit;
211 213 }
212 214
213 215 Py_INCREF(Py_None);
214 216 return Py_None;
215 217 quit:
216 218 return NULL;
217 219 }
218 220
219 221 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
220 222 int size, int mtime)
221 223 {
222 224 dirstateTupleObject *t = PyObject_New(dirstateTupleObject,
223 225 &dirstateTupleType);
224 226 if (!t)
225 227 return NULL;
226 228 t->state = state;
227 229 t->mode = mode;
228 230 t->size = size;
229 231 t->mtime = mtime;
230 232 return t;
231 233 }
232 234
233 235 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
234 236 PyObject *kwds)
235 237 {
236 238 /* We do all the initialization here and not a tp_init function because
237 239 * dirstate_tuple is immutable. */
238 240 dirstateTupleObject *t;
239 241 char state;
240 242 int size, mode, mtime;
241 243 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
242 244 return NULL;
243 245
244 246 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
245 247 if (!t)
246 248 return NULL;
247 249 t->state = state;
248 250 t->mode = mode;
249 251 t->size = size;
250 252 t->mtime = mtime;
251 253
252 254 return (PyObject *)t;
253 255 }
254 256
255 257 static void dirstate_tuple_dealloc(PyObject *o)
256 258 {
257 259 PyObject_Del(o);
258 260 }
259 261
260 262 static Py_ssize_t dirstate_tuple_length(PyObject *o)
261 263 {
262 264 return 4;
263 265 }
264 266
265 267 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
266 268 {
267 269 dirstateTupleObject *t = (dirstateTupleObject *)o;
268 270 switch (i) {
269 271 case 0:
270 272 return PyBytes_FromStringAndSize(&t->state, 1);
271 273 case 1:
272 274 return PyInt_FromLong(t->mode);
273 275 case 2:
274 276 return PyInt_FromLong(t->size);
275 277 case 3:
276 278 return PyInt_FromLong(t->mtime);
277 279 default:
278 280 PyErr_SetString(PyExc_IndexError, "index out of range");
279 281 return NULL;
280 282 }
281 283 }
282 284
283 285 static PySequenceMethods dirstate_tuple_sq = {
284 286 dirstate_tuple_length, /* sq_length */
285 287 0, /* sq_concat */
286 288 0, /* sq_repeat */
287 289 dirstate_tuple_item, /* sq_item */
288 290 0, /* sq_ass_item */
289 291 0, /* sq_contains */
290 292 0, /* sq_inplace_concat */
291 293 0 /* sq_inplace_repeat */
292 294 };
293 295
294 296 PyTypeObject dirstateTupleType = {
295 297 PyVarObject_HEAD_INIT(NULL, 0)
296 298 "dirstate_tuple", /* tp_name */
297 299 sizeof(dirstateTupleObject),/* tp_basicsize */
298 300 0, /* tp_itemsize */
299 301 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
300 302 0, /* tp_print */
301 303 0, /* tp_getattr */
302 304 0, /* tp_setattr */
303 305 0, /* tp_compare */
304 306 0, /* tp_repr */
305 307 0, /* tp_as_number */
306 308 &dirstate_tuple_sq, /* tp_as_sequence */
307 309 0, /* tp_as_mapping */
308 310 0, /* tp_hash */
309 311 0, /* tp_call */
310 312 0, /* tp_str */
311 313 0, /* tp_getattro */
312 314 0, /* tp_setattro */
313 315 0, /* tp_as_buffer */
314 316 Py_TPFLAGS_DEFAULT, /* tp_flags */
315 317 "dirstate tuple", /* tp_doc */
316 318 0, /* tp_traverse */
317 319 0, /* tp_clear */
318 320 0, /* tp_richcompare */
319 321 0, /* tp_weaklistoffset */
320 322 0, /* tp_iter */
321 323 0, /* tp_iternext */
322 324 0, /* tp_methods */
323 325 0, /* tp_members */
324 326 0, /* tp_getset */
325 327 0, /* tp_base */
326 328 0, /* tp_dict */
327 329 0, /* tp_descr_get */
328 330 0, /* tp_descr_set */
329 331 0, /* tp_dictoffset */
330 332 0, /* tp_init */
331 333 0, /* tp_alloc */
332 334 dirstate_tuple_new, /* tp_new */
333 335 };
334 336
335 337 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
336 338 {
337 339 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
338 340 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
339 341 char state, *cur, *str, *cpos;
340 342 int mode, size, mtime;
341 343 unsigned int flen, len, pos = 40;
342 344 int readlen;
343 345
344 346 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
345 347 &PyDict_Type, &dmap,
346 348 &PyDict_Type, &cmap,
347 349 &str, &readlen))
348 350 goto quit;
349 351
350 352 if (readlen < 0)
351 353 goto quit;
352 354
353 355 len = readlen;
354 356
355 357 /* read parents */
356 358 if (len < 40)
357 359 goto quit;
358 360
359 361 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
360 362 if (!parents)
361 363 goto quit;
362 364
363 365 /* read filenames */
364 366 while (pos >= 40 && pos < len) {
365 367 cur = str + pos;
366 368 /* unpack header */
367 369 state = *cur;
368 370 mode = getbe32(cur + 1);
369 371 size = getbe32(cur + 5);
370 372 mtime = getbe32(cur + 9);
371 373 flen = getbe32(cur + 13);
372 374 pos += 17;
373 375 cur += 17;
374 376 if (flen > len - pos) {
375 377 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
376 378 goto quit;
377 379 }
378 380
379 381 entry = (PyObject *)make_dirstate_tuple(state, mode, size,
380 382 mtime);
381 383 cpos = memchr(cur, 0, flen);
382 384 if (cpos) {
383 385 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
384 386 cname = PyBytes_FromStringAndSize(cpos + 1,
385 387 flen - (cpos - cur) - 1);
386 388 if (!fname || !cname ||
387 389 PyDict_SetItem(cmap, fname, cname) == -1 ||
388 390 PyDict_SetItem(dmap, fname, entry) == -1)
389 391 goto quit;
390 392 Py_DECREF(cname);
391 393 } else {
392 394 fname = PyBytes_FromStringAndSize(cur, flen);
393 395 if (!fname ||
394 396 PyDict_SetItem(dmap, fname, entry) == -1)
395 397 goto quit;
396 398 }
397 399 Py_DECREF(fname);
398 400 Py_DECREF(entry);
399 401 fname = cname = entry = NULL;
400 402 pos += flen;
401 403 }
402 404
403 405 ret = parents;
404 406 Py_INCREF(ret);
405 407 quit:
406 408 Py_XDECREF(fname);
407 409 Py_XDECREF(cname);
408 410 Py_XDECREF(entry);
409 411 Py_XDECREF(parents);
410 412 return ret;
411 413 }
412 414
413 415 /*
414 416 * Efficiently pack a dirstate object into its on-disk format.
415 417 */
416 418 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
417 419 {
418 420 PyObject *packobj = NULL;
419 421 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
420 422 Py_ssize_t nbytes, pos, l;
421 423 PyObject *k, *v = NULL, *pn;
422 424 char *p, *s;
423 425 double now;
424 426
425 427 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
426 428 &PyDict_Type, &map, &PyDict_Type, &copymap,
427 429 &pl, &now))
428 430 return NULL;
429 431
430 432 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
431 433 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
432 434 return NULL;
433 435 }
434 436
435 437 /* Figure out how much we need to allocate. */
436 438 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
437 439 PyObject *c;
438 440 if (!PyString_Check(k)) {
439 441 PyErr_SetString(PyExc_TypeError, "expected string key");
440 442 goto bail;
441 443 }
442 444 nbytes += PyString_GET_SIZE(k) + 17;
443 445 c = PyDict_GetItem(copymap, k);
444 446 if (c) {
445 447 if (!PyString_Check(c)) {
446 448 PyErr_SetString(PyExc_TypeError,
447 449 "expected string key");
448 450 goto bail;
449 451 }
450 452 nbytes += PyString_GET_SIZE(c) + 1;
451 453 }
452 454 }
453 455
454 456 packobj = PyString_FromStringAndSize(NULL, nbytes);
455 457 if (packobj == NULL)
456 458 goto bail;
457 459
458 460 p = PyString_AS_STRING(packobj);
459 461
460 462 pn = PySequence_ITEM(pl, 0);
461 463 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
462 464 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
463 465 goto bail;
464 466 }
465 467 memcpy(p, s, l);
466 468 p += 20;
467 469 pn = PySequence_ITEM(pl, 1);
468 470 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
469 471 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
470 472 goto bail;
471 473 }
472 474 memcpy(p, s, l);
473 475 p += 20;
474 476
475 477 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
476 478 dirstateTupleObject *tuple;
477 479 char state;
478 480 uint32_t mode, size, mtime;
479 481 Py_ssize_t len, l;
480 482 PyObject *o;
481 483 char *t;
482 484
483 485 if (!dirstate_tuple_check(v)) {
484 486 PyErr_SetString(PyExc_TypeError,
485 487 "expected a dirstate tuple");
486 488 goto bail;
487 489 }
488 490 tuple = (dirstateTupleObject *)v;
489 491
490 492 state = tuple->state;
491 493 mode = tuple->mode;
492 494 size = tuple->size;
493 495 mtime = tuple->mtime;
494 496 if (state == 'n' && mtime == (uint32_t)now) {
495 497 /* See pure/parsers.py:pack_dirstate for why we do
496 498 * this. */
497 499 mtime = -1;
498 500 mtime_unset = (PyObject *)make_dirstate_tuple(
499 501 state, mode, size, mtime);
500 502 if (!mtime_unset)
501 503 goto bail;
502 504 if (PyDict_SetItem(map, k, mtime_unset) == -1)
503 505 goto bail;
504 506 Py_DECREF(mtime_unset);
505 507 mtime_unset = NULL;
506 508 }
507 509 *p++ = state;
508 510 putbe32(mode, p);
509 511 putbe32(size, p + 4);
510 512 putbe32(mtime, p + 8);
511 513 t = p + 12;
512 514 p += 16;
513 515 len = PyString_GET_SIZE(k);
514 516 memcpy(p, PyString_AS_STRING(k), len);
515 517 p += len;
516 518 o = PyDict_GetItem(copymap, k);
517 519 if (o) {
518 520 *p++ = '\0';
519 521 l = PyString_GET_SIZE(o);
520 522 memcpy(p, PyString_AS_STRING(o), l);
521 523 p += l;
522 524 len += l + 1;
523 525 }
524 526 putbe32((uint32_t)len, t);
525 527 }
526 528
527 529 pos = p - PyString_AS_STRING(packobj);
528 530 if (pos != nbytes) {
529 531 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
530 532 (long)pos, (long)nbytes);
531 533 goto bail;
532 534 }
533 535
534 536 return packobj;
535 537 bail:
536 538 Py_XDECREF(mtime_unset);
537 539 Py_XDECREF(packobj);
538 540 Py_XDECREF(v);
539 541 return NULL;
540 542 }
541 543
542 544 /*
543 545 * A base-16 trie for fast node->rev mapping.
544 546 *
545 547 * Positive value is index of the next node in the trie
546 548 * Negative value is a leaf: -(rev + 1)
547 549 * Zero is empty
548 550 */
549 551 typedef struct {
550 552 int children[16];
551 553 } nodetree;
552 554
553 555 /*
554 556 * This class has two behaviours.
555 557 *
556 558 * When used in a list-like way (with integer keys), we decode an
557 559 * entry in a RevlogNG index file on demand. Our last entry is a
558 560 * sentinel, always a nullid. We have limited support for
559 561 * integer-keyed insert and delete, only at elements right before the
560 562 * sentinel.
561 563 *
562 564 * With string keys, we lazily perform a reverse mapping from node to
563 565 * rev, using a base-16 trie.
564 566 */
565 567 typedef struct {
566 568 PyObject_HEAD
567 569 /* Type-specific fields go here. */
568 570 PyObject *data; /* raw bytes of index */
569 571 PyObject **cache; /* cached tuples */
570 572 const char **offsets; /* populated on demand */
571 573 Py_ssize_t raw_length; /* original number of elements */
572 574 Py_ssize_t length; /* current number of elements */
573 575 PyObject *added; /* populated on demand */
574 576 PyObject *headrevs; /* cache, invalidated on changes */
575 577 PyObject *filteredrevs;/* filtered revs set */
576 578 nodetree *nt; /* base-16 trie */
577 579 int ntlength; /* # nodes in use */
578 580 int ntcapacity; /* # nodes allocated */
579 581 int ntdepth; /* maximum depth of tree */
580 582 int ntsplits; /* # splits performed */
581 583 int ntrev; /* last rev scanned */
582 584 int ntlookups; /* # lookups */
583 585 int ntmisses; /* # lookups that miss the cache */
584 586 int inlined;
585 587 } indexObject;
586 588
587 589 static Py_ssize_t index_length(const indexObject *self)
588 590 {
589 591 if (self->added == NULL)
590 592 return self->length;
591 593 return self->length + PyList_GET_SIZE(self->added);
592 594 }
593 595
594 596 static PyObject *nullentry;
595 597 static const char nullid[20];
596 598
597 599 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
598 600
599 601 #if LONG_MAX == 0x7fffffffL
600 602 static char *tuple_format = "Kiiiiiis#";
601 603 #else
602 604 static char *tuple_format = "kiiiiiis#";
603 605 #endif
604 606
605 607 /* A RevlogNG v1 index entry is 64 bytes long. */
606 608 static const long v1_hdrsize = 64;
607 609
608 610 /*
609 611 * Return a pointer to the beginning of a RevlogNG record.
610 612 */
611 613 static const char *index_deref(indexObject *self, Py_ssize_t pos)
612 614 {
613 615 if (self->inlined && pos > 0) {
614 616 if (self->offsets == NULL) {
615 617 self->offsets = malloc(self->raw_length *
616 618 sizeof(*self->offsets));
617 619 if (self->offsets == NULL)
618 620 return (const char *)PyErr_NoMemory();
619 621 inline_scan(self, self->offsets);
620 622 }
621 623 return self->offsets[pos];
622 624 }
623 625
624 626 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
625 627 }
626 628
627 629 /*
628 630 * RevlogNG format (all in big endian, data may be inlined):
629 631 * 6 bytes: offset
630 632 * 2 bytes: flags
631 633 * 4 bytes: compressed length
632 634 * 4 bytes: uncompressed length
633 635 * 4 bytes: base revision
634 636 * 4 bytes: link revision
635 637 * 4 bytes: parent 1 revision
636 638 * 4 bytes: parent 2 revision
637 639 * 32 bytes: nodeid (only 20 bytes used)
638 640 */
639 641 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
640 642 {
641 643 uint64_t offset_flags;
642 644 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
643 645 const char *c_node_id;
644 646 const char *data;
645 647 Py_ssize_t length = index_length(self);
646 648 PyObject *entry;
647 649
648 650 if (pos < 0)
649 651 pos += length;
650 652
651 653 if (pos < 0 || pos >= length) {
652 654 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
653 655 return NULL;
654 656 }
655 657
656 658 if (pos == length - 1) {
657 659 Py_INCREF(nullentry);
658 660 return nullentry;
659 661 }
660 662
661 663 if (pos >= self->length - 1) {
662 664 PyObject *obj;
663 665 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
664 666 Py_INCREF(obj);
665 667 return obj;
666 668 }
667 669
668 670 if (self->cache) {
669 671 if (self->cache[pos]) {
670 672 Py_INCREF(self->cache[pos]);
671 673 return self->cache[pos];
672 674 }
673 675 } else {
674 676 self->cache = calloc(self->raw_length, sizeof(PyObject *));
675 677 if (self->cache == NULL)
676 678 return PyErr_NoMemory();
677 679 }
678 680
679 681 data = index_deref(self, pos);
680 682 if (data == NULL)
681 683 return NULL;
682 684
683 685 offset_flags = getbe32(data + 4);
684 686 if (pos == 0) /* mask out version number for the first entry */
685 687 offset_flags &= 0xFFFF;
686 688 else {
687 689 uint32_t offset_high = getbe32(data);
688 690 offset_flags |= ((uint64_t)offset_high) << 32;
689 691 }
690 692
691 693 comp_len = getbe32(data + 8);
692 694 uncomp_len = getbe32(data + 12);
693 695 base_rev = getbe32(data + 16);
694 696 link_rev = getbe32(data + 20);
695 697 parent_1 = getbe32(data + 24);
696 698 parent_2 = getbe32(data + 28);
697 699 c_node_id = data + 32;
698 700
699 701 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
700 702 uncomp_len, base_rev, link_rev,
701 703 parent_1, parent_2, c_node_id, 20);
702 704
703 705 if (entry) {
704 706 PyObject_GC_UnTrack(entry);
705 707 Py_INCREF(entry);
706 708 }
707 709
708 710 self->cache[pos] = entry;
709 711
710 712 return entry;
711 713 }
712 714
713 715 /*
714 716 * Return the 20-byte SHA of the node corresponding to the given rev.
715 717 */
716 718 static const char *index_node(indexObject *self, Py_ssize_t pos)
717 719 {
718 720 Py_ssize_t length = index_length(self);
719 721 const char *data;
720 722
721 723 if (pos == length - 1 || pos == INT_MAX)
722 724 return nullid;
723 725
724 726 if (pos >= length)
725 727 return NULL;
726 728
727 729 if (pos >= self->length - 1) {
728 730 PyObject *tuple, *str;
729 731 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
730 732 str = PyTuple_GetItem(tuple, 7);
731 733 return str ? PyString_AS_STRING(str) : NULL;
732 734 }
733 735
734 736 data = index_deref(self, pos);
735 737 return data ? data + 32 : NULL;
736 738 }
737 739
738 740 static int nt_insert(indexObject *self, const char *node, int rev);
739 741
740 742 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
741 743 {
742 744 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
743 745 return -1;
744 746 if (*nodelen == 20)
745 747 return 0;
746 748 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
747 749 return -1;
748 750 }
749 751
750 752 static PyObject *index_insert(indexObject *self, PyObject *args)
751 753 {
752 754 PyObject *obj;
753 755 char *node;
754 756 int index;
755 757 Py_ssize_t len, nodelen;
756 758
757 759 if (!PyArg_ParseTuple(args, "iO", &index, &obj))
758 760 return NULL;
759 761
760 762 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
761 763 PyErr_SetString(PyExc_TypeError, "8-tuple required");
762 764 return NULL;
763 765 }
764 766
765 767 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
766 768 return NULL;
767 769
768 770 len = index_length(self);
769 771
770 772 if (index < 0)
771 773 index += len;
772 774
773 775 if (index != len - 1) {
774 776 PyErr_SetString(PyExc_IndexError,
775 777 "insert only supported at index -1");
776 778 return NULL;
777 779 }
778 780
779 781 if (self->added == NULL) {
780 782 self->added = PyList_New(0);
781 783 if (self->added == NULL)
782 784 return NULL;
783 785 }
784 786
785 787 if (PyList_Append(self->added, obj) == -1)
786 788 return NULL;
787 789
788 790 if (self->nt)
789 791 nt_insert(self, node, index);
790 792
791 793 Py_CLEAR(self->headrevs);
792 794 Py_RETURN_NONE;
793 795 }
794 796
795 797 static void _index_clearcaches(indexObject *self)
796 798 {
797 799 if (self->cache) {
798 800 Py_ssize_t i;
799 801
800 802 for (i = 0; i < self->raw_length; i++)
801 803 Py_CLEAR(self->cache[i]);
802 804 free(self->cache);
803 805 self->cache = NULL;
804 806 }
805 807 if (self->offsets) {
806 808 free(self->offsets);
807 809 self->offsets = NULL;
808 810 }
809 811 if (self->nt) {
810 812 free(self->nt);
811 813 self->nt = NULL;
812 814 }
813 815 Py_CLEAR(self->headrevs);
814 816 }
815 817
816 818 static PyObject *index_clearcaches(indexObject *self)
817 819 {
818 820 _index_clearcaches(self);
819 821 self->ntlength = self->ntcapacity = 0;
820 822 self->ntdepth = self->ntsplits = 0;
821 823 self->ntrev = -1;
822 824 self->ntlookups = self->ntmisses = 0;
823 825 Py_RETURN_NONE;
824 826 }
825 827
826 828 static PyObject *index_stats(indexObject *self)
827 829 {
828 830 PyObject *obj = PyDict_New();
829 831 PyObject *t = NULL;
830 832
831 833 if (obj == NULL)
832 834 return NULL;
833 835
834 836 #define istat(__n, __d) \
835 837 t = PyInt_FromSsize_t(self->__n); \
836 838 if (!t) \
837 839 goto bail; \
838 840 if (PyDict_SetItemString(obj, __d, t) == -1) \
839 841 goto bail; \
840 842 Py_DECREF(t);
841 843
842 844 if (self->added) {
843 845 Py_ssize_t len = PyList_GET_SIZE(self->added);
844 846 t = PyInt_FromSsize_t(len);
845 847 if (!t)
846 848 goto bail;
847 849 if (PyDict_SetItemString(obj, "index entries added", t) == -1)
848 850 goto bail;
849 851 Py_DECREF(t);
850 852 }
851 853
852 854 if (self->raw_length != self->length - 1)
853 855 istat(raw_length, "revs on disk");
854 856 istat(length, "revs in memory");
855 857 istat(ntcapacity, "node trie capacity");
856 858 istat(ntdepth, "node trie depth");
857 859 istat(ntlength, "node trie count");
858 860 istat(ntlookups, "node trie lookups");
859 861 istat(ntmisses, "node trie misses");
860 862 istat(ntrev, "node trie last rev scanned");
861 863 istat(ntsplits, "node trie splits");
862 864
863 865 #undef istat
864 866
865 867 return obj;
866 868
867 869 bail:
868 870 Py_XDECREF(obj);
869 871 Py_XDECREF(t);
870 872 return NULL;
871 873 }
872 874
873 875 /*
874 876 * When we cache a list, we want to be sure the caller can't mutate
875 877 * the cached copy.
876 878 */
877 879 static PyObject *list_copy(PyObject *list)
878 880 {
879 881 Py_ssize_t len = PyList_GET_SIZE(list);
880 882 PyObject *newlist = PyList_New(len);
881 883 Py_ssize_t i;
882 884
883 885 if (newlist == NULL)
884 886 return NULL;
885 887
886 888 for (i = 0; i < len; i++) {
887 889 PyObject *obj = PyList_GET_ITEM(list, i);
888 890 Py_INCREF(obj);
889 891 PyList_SET_ITEM(newlist, i, obj);
890 892 }
891 893
892 894 return newlist;
893 895 }
894 896
895 897 /* arg should be Py_ssize_t but Python 2.4 do not support the n format */
896 898 static int check_filter(PyObject *filter, unsigned long arg) {
897 899 if (filter) {
898 900 PyObject *arglist, *result;
899 901 int isfiltered;
900 902
901 903 arglist = Py_BuildValue("(k)", arg);
902 904 if (!arglist) {
903 905 return -1;
904 906 }
905 907
906 908 result = PyEval_CallObject(filter, arglist);
907 909 Py_DECREF(arglist);
908 910 if (!result) {
909 911 return -1;
910 912 }
911 913
912 914 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
913 915 * same as this function, so we can just return it directly.*/
914 916 isfiltered = PyObject_IsTrue(result);
915 917 Py_DECREF(result);
916 918 return isfiltered;
917 919 } else {
918 920 return 0;
919 921 }
920 922 }
921 923
922 924 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
923 925 Py_ssize_t marker, char *phases)
924 926 {
925 927 PyObject *iter = NULL;
926 928 PyObject *iter_item = NULL;
927 929 Py_ssize_t min_idx = index_length(self) + 1;
928 930 long iter_item_long;
929 931
930 932 if (PyList_GET_SIZE(list) != 0) {
931 933 iter = PyObject_GetIter(list);
932 934 if (iter == NULL)
933 935 return -2;
934 936 while ((iter_item = PyIter_Next(iter)))
935 937 {
936 938 iter_item_long = PyInt_AS_LONG(iter_item);
937 939 Py_DECREF(iter_item);
938 940 if (iter_item_long < min_idx)
939 941 min_idx = iter_item_long;
940 942 phases[iter_item_long] = marker;
941 943 }
942 944 Py_DECREF(iter);
943 945 }
944 946
945 947 return min_idx;
946 948 }
947 949
948 950 static inline void set_phase_from_parents(char *phases, int parent_1,
949 951 int parent_2, Py_ssize_t i)
950 952 {
951 953 if (parent_1 >= 0 && phases[parent_1] > phases[i])
952 954 phases[i] = phases[parent_1];
953 955 if (parent_2 >= 0 && phases[parent_2] > phases[i])
954 956 phases[i] = phases[parent_2];
955 957 }
956 958
957 959 static PyObject *compute_phases(indexObject *self, PyObject *args)
958 960 {
959 961 PyObject *roots = Py_None;
960 962 PyObject *phaseslist = NULL;
961 963 PyObject *phaseroots = NULL;
962 964 PyObject *rev = NULL;
963 965 PyObject *p1 = NULL;
964 966 PyObject *p2 = NULL;
965 967 Py_ssize_t addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
966 968 Py_ssize_t len = index_length(self) - 1;
967 969 Py_ssize_t numphase = 0;
968 970 Py_ssize_t minrevallphases = 0;
969 971 Py_ssize_t minrevphase = 0;
970 972 Py_ssize_t i = 0;
971 973 int parent_1, parent_2;
972 974 char *phases = NULL;
973 975 const char *data;
974 976
975 977 if (!PyArg_ParseTuple(args, "O", &roots))
976 978 goto release_none;
977 979 if (roots == NULL || !PyList_Check(roots))
978 980 goto release_none;
979 981
980 982 phases = calloc(len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
981 983 if (phases == NULL)
982 984 goto release_none;
983 985 /* Put the phase information of all the roots in phases */
984 986 numphase = PyList_GET_SIZE(roots)+1;
985 987 minrevallphases = len + 1;
986 988 for (i = 0; i < numphase-1; i++) {
987 989 phaseroots = PyList_GET_ITEM(roots, i);
988 990 if (!PyList_Check(phaseroots))
989 991 goto release_phases;
990 992 minrevphase = add_roots_get_min(self, phaseroots, i+1, phases);
991 993 if (minrevphase == -2) /* Error from add_roots_get_min */
992 994 goto release_phases;
993 995 minrevallphases = MIN(minrevallphases, minrevphase);
994 996 }
995 997 /* Propagate the phase information from the roots to the revs */
996 998 if (minrevallphases != -1) {
997 999 for (i = minrevallphases; i < self->raw_length; i++) {
998 1000 data = index_deref(self, i);
999 1001 set_phase_from_parents(phases, getbe32(data+24), getbe32(data+28), i);
1000 1002 }
1001 1003 for (i = 0; i < addlen; i++) {
1002 1004 rev = PyList_GET_ITEM(self->added, i);
1003 1005 p1 = PyTuple_GET_ITEM(rev, 5);
1004 1006 p2 = PyTuple_GET_ITEM(rev, 6);
1005 1007 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1006 1008 PyErr_SetString(PyExc_TypeError, "revlog parents are invalid");
1007 1009 goto release_phases;
1008 1010 }
1009 1011 parent_1 = (int)PyInt_AS_LONG(p1);
1010 1012 parent_2 = (int)PyInt_AS_LONG(p2);
1011 1013 set_phase_from_parents(phases, parent_1, parent_2, i+self->raw_length);
1012 1014 }
1013 1015 }
1014 1016 /* Transform phase list to a python list */
1015 1017 phaseslist = PyList_New(len);
1016 1018 if (phaseslist == NULL)
1017 1019 goto release_phases;
1018 1020 for (i = 0; i < len; i++)
1019 1021 PyList_SET_ITEM(phaseslist, i, PyInt_FromLong(phases[i]));
1020 1022
1021 1023 release_phases:
1022 1024 free(phases);
1023 1025 release_none:
1024 1026 return phaseslist;
1025 1027 }
1026 1028
1027 1029 static PyObject *index_headrevs(indexObject *self, PyObject *args)
1028 1030 {
1029 1031 Py_ssize_t i, len, addlen;
1030 1032 char *nothead = NULL;
1031 1033 PyObject *heads = NULL;
1032 1034 PyObject *filter = NULL;
1033 1035 PyObject *filteredrevs = Py_None;
1034 1036
1035 1037 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
1036 1038 return NULL;
1037 1039 }
1038 1040
1039 1041 if (self->headrevs && filteredrevs == self->filteredrevs)
1040 1042 return list_copy(self->headrevs);
1041 1043
1042 1044 Py_DECREF(self->filteredrevs);
1043 1045 self->filteredrevs = filteredrevs;
1044 1046 Py_INCREF(filteredrevs);
1045 1047
1046 1048 if (filteredrevs != Py_None) {
1047 1049 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
1048 1050 if (!filter) {
1049 1051 PyErr_SetString(PyExc_TypeError,
1050 1052 "filteredrevs has no attribute __contains__");
1051 1053 goto bail;
1052 1054 }
1053 1055 }
1054 1056
1055 1057 len = index_length(self) - 1;
1056 1058 heads = PyList_New(0);
1057 1059 if (heads == NULL)
1058 1060 goto bail;
1059 1061 if (len == 0) {
1060 1062 PyObject *nullid = PyInt_FromLong(-1);
1061 1063 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
1062 1064 Py_XDECREF(nullid);
1063 1065 goto bail;
1064 1066 }
1065 1067 goto done;
1066 1068 }
1067 1069
1068 1070 nothead = calloc(len, 1);
1069 1071 if (nothead == NULL)
1070 1072 goto bail;
1071 1073
1072 1074 for (i = 0; i < self->raw_length; i++) {
1073 1075 const char *data;
1074 1076 int parent_1, parent_2, isfiltered;
1075 1077
1076 1078 isfiltered = check_filter(filter, i);
1077 1079 if (isfiltered == -1) {
1078 1080 PyErr_SetString(PyExc_TypeError,
1079 1081 "unable to check filter");
1080 1082 goto bail;
1081 1083 }
1082 1084
1083 1085 if (isfiltered) {
1084 1086 nothead[i] = 1;
1085 1087 continue;
1086 1088 }
1087 1089
1088 1090 data = index_deref(self, i);
1089 1091 parent_1 = getbe32(data + 24);
1090 1092 parent_2 = getbe32(data + 28);
1091 1093
1092 1094 if (parent_1 >= 0)
1093 1095 nothead[parent_1] = 1;
1094 1096 if (parent_2 >= 0)
1095 1097 nothead[parent_2] = 1;
1096 1098 }
1097 1099
1098 1100 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
1099 1101
1100 1102 for (i = 0; i < addlen; i++) {
1101 1103 PyObject *rev = PyList_GET_ITEM(self->added, i);
1102 1104 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
1103 1105 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
1104 1106 long parent_1, parent_2;
1105 1107 int isfiltered;
1106 1108
1107 1109 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1108 1110 PyErr_SetString(PyExc_TypeError,
1109 1111 "revlog parents are invalid");
1110 1112 goto bail;
1111 1113 }
1112 1114
1113 1115 isfiltered = check_filter(filter, i);
1114 1116 if (isfiltered == -1) {
1115 1117 PyErr_SetString(PyExc_TypeError,
1116 1118 "unable to check filter");
1117 1119 goto bail;
1118 1120 }
1119 1121
1120 1122 if (isfiltered) {
1121 1123 nothead[i] = 1;
1122 1124 continue;
1123 1125 }
1124 1126
1125 1127 parent_1 = PyInt_AS_LONG(p1);
1126 1128 parent_2 = PyInt_AS_LONG(p2);
1127 1129 if (parent_1 >= 0)
1128 1130 nothead[parent_1] = 1;
1129 1131 if (parent_2 >= 0)
1130 1132 nothead[parent_2] = 1;
1131 1133 }
1132 1134
1133 1135 for (i = 0; i < len; i++) {
1134 1136 PyObject *head;
1135 1137
1136 1138 if (nothead[i])
1137 1139 continue;
1138 1140 head = PyInt_FromSsize_t(i);
1139 1141 if (head == NULL || PyList_Append(heads, head) == -1) {
1140 1142 Py_XDECREF(head);
1141 1143 goto bail;
1142 1144 }
1143 1145 }
1144 1146
1145 1147 done:
1146 1148 self->headrevs = heads;
1147 1149 Py_XDECREF(filter);
1148 1150 free(nothead);
1149 1151 return list_copy(self->headrevs);
1150 1152 bail:
1151 1153 Py_XDECREF(filter);
1152 1154 Py_XDECREF(heads);
1153 1155 free(nothead);
1154 1156 return NULL;
1155 1157 }
1156 1158
1157 1159 static inline int nt_level(const char *node, Py_ssize_t level)
1158 1160 {
1159 1161 int v = node[level>>1];
1160 1162 if (!(level & 1))
1161 1163 v >>= 4;
1162 1164 return v & 0xf;
1163 1165 }
1164 1166
1165 1167 /*
1166 1168 * Return values:
1167 1169 *
1168 1170 * -4: match is ambiguous (multiple candidates)
1169 1171 * -2: not found
1170 1172 * rest: valid rev
1171 1173 */
1172 1174 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
1173 1175 int hex)
1174 1176 {
1175 1177 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1176 1178 int level, maxlevel, off;
1177 1179
1178 1180 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1179 1181 return -1;
1180 1182
1181 1183 if (self->nt == NULL)
1182 1184 return -2;
1183 1185
1184 1186 if (hex)
1185 1187 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1186 1188 else
1187 1189 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1188 1190
1189 1191 for (level = off = 0; level < maxlevel; level++) {
1190 1192 int k = getnybble(node, level);
1191 1193 nodetree *n = &self->nt[off];
1192 1194 int v = n->children[k];
1193 1195
1194 1196 if (v < 0) {
1195 1197 const char *n;
1196 1198 Py_ssize_t i;
1197 1199
1198 1200 v = -v - 1;
1199 1201 n = index_node(self, v);
1200 1202 if (n == NULL)
1201 1203 return -2;
1202 1204 for (i = level; i < maxlevel; i++)
1203 1205 if (getnybble(node, i) != nt_level(n, i))
1204 1206 return -2;
1205 1207 return v;
1206 1208 }
1207 1209 if (v == 0)
1208 1210 return -2;
1209 1211 off = v;
1210 1212 }
1211 1213 /* multiple matches against an ambiguous prefix */
1212 1214 return -4;
1213 1215 }
1214 1216
1215 1217 static int nt_new(indexObject *self)
1216 1218 {
1217 1219 if (self->ntlength == self->ntcapacity) {
1218 1220 self->ntcapacity *= 2;
1219 1221 self->nt = realloc(self->nt,
1220 1222 self->ntcapacity * sizeof(nodetree));
1221 1223 if (self->nt == NULL) {
1222 1224 PyErr_SetString(PyExc_MemoryError, "out of memory");
1223 1225 return -1;
1224 1226 }
1225 1227 memset(&self->nt[self->ntlength], 0,
1226 1228 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
1227 1229 }
1228 1230 return self->ntlength++;
1229 1231 }
1230 1232
1231 1233 static int nt_insert(indexObject *self, const char *node, int rev)
1232 1234 {
1233 1235 int level = 0;
1234 1236 int off = 0;
1235 1237
1236 1238 while (level < 40) {
1237 1239 int k = nt_level(node, level);
1238 1240 nodetree *n;
1239 1241 int v;
1240 1242
1241 1243 n = &self->nt[off];
1242 1244 v = n->children[k];
1243 1245
1244 1246 if (v == 0) {
1245 1247 n->children[k] = -rev - 1;
1246 1248 return 0;
1247 1249 }
1248 1250 if (v < 0) {
1249 1251 const char *oldnode = index_node(self, -v - 1);
1250 1252 int noff;
1251 1253
1252 1254 if (!oldnode || !memcmp(oldnode, node, 20)) {
1253 1255 n->children[k] = -rev - 1;
1254 1256 return 0;
1255 1257 }
1256 1258 noff = nt_new(self);
1257 1259 if (noff == -1)
1258 1260 return -1;
1259 1261 /* self->nt may have been changed by realloc */
1260 1262 self->nt[off].children[k] = noff;
1261 1263 off = noff;
1262 1264 n = &self->nt[off];
1263 1265 n->children[nt_level(oldnode, ++level)] = v;
1264 1266 if (level > self->ntdepth)
1265 1267 self->ntdepth = level;
1266 1268 self->ntsplits += 1;
1267 1269 } else {
1268 1270 level += 1;
1269 1271 off = v;
1270 1272 }
1271 1273 }
1272 1274
1273 1275 return -1;
1274 1276 }
1275 1277
1276 1278 static int nt_init(indexObject *self)
1277 1279 {
1278 1280 if (self->nt == NULL) {
1279 1281 if (self->raw_length > INT_MAX) {
1280 1282 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1281 1283 return -1;
1282 1284 }
1283 1285 self->ntcapacity = self->raw_length < 4
1284 1286 ? 4 : (int)self->raw_length / 2;
1285 1287
1286 1288 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1287 1289 if (self->nt == NULL) {
1288 1290 PyErr_NoMemory();
1289 1291 return -1;
1290 1292 }
1291 1293 self->ntlength = 1;
1292 1294 self->ntrev = (int)index_length(self) - 1;
1293 1295 self->ntlookups = 1;
1294 1296 self->ntmisses = 0;
1295 1297 if (nt_insert(self, nullid, INT_MAX) == -1)
1296 1298 return -1;
1297 1299 }
1298 1300 return 0;
1299 1301 }
1300 1302
1301 1303 /*
1302 1304 * Return values:
1303 1305 *
1304 1306 * -3: error (exception set)
1305 1307 * -2: not found (no exception set)
1306 1308 * rest: valid rev
1307 1309 */
1308 1310 static int index_find_node(indexObject *self,
1309 1311 const char *node, Py_ssize_t nodelen)
1310 1312 {
1311 1313 int rev;
1312 1314
1313 1315 self->ntlookups++;
1314 1316 rev = nt_find(self, node, nodelen, 0);
1315 1317 if (rev >= -1)
1316 1318 return rev;
1317 1319
1318 1320 if (nt_init(self) == -1)
1319 1321 return -3;
1320 1322
1321 1323 /*
1322 1324 * For the first handful of lookups, we scan the entire index,
1323 1325 * and cache only the matching nodes. This optimizes for cases
1324 1326 * like "hg tip", where only a few nodes are accessed.
1325 1327 *
1326 1328 * After that, we cache every node we visit, using a single
1327 1329 * scan amortized over multiple lookups. This gives the best
1328 1330 * bulk performance, e.g. for "hg log".
1329 1331 */
1330 1332 if (self->ntmisses++ < 4) {
1331 1333 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1332 1334 const char *n = index_node(self, rev);
1333 1335 if (n == NULL)
1334 1336 return -2;
1335 1337 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1336 1338 if (nt_insert(self, n, rev) == -1)
1337 1339 return -3;
1338 1340 break;
1339 1341 }
1340 1342 }
1341 1343 } else {
1342 1344 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1343 1345 const char *n = index_node(self, rev);
1344 1346 if (n == NULL) {
1345 1347 self->ntrev = rev + 1;
1346 1348 return -2;
1347 1349 }
1348 1350 if (nt_insert(self, n, rev) == -1) {
1349 1351 self->ntrev = rev + 1;
1350 1352 return -3;
1351 1353 }
1352 1354 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1353 1355 break;
1354 1356 }
1355 1357 }
1356 1358 self->ntrev = rev;
1357 1359 }
1358 1360
1359 1361 if (rev >= 0)
1360 1362 return rev;
1361 1363 return -2;
1362 1364 }
1363 1365
1364 1366 static PyObject *raise_revlog_error(void)
1365 1367 {
1366 1368 static PyObject *errclass;
1367 1369 PyObject *mod = NULL, *errobj;
1368 1370
1369 1371 if (errclass == NULL) {
1370 1372 PyObject *dict;
1371 1373
1372 1374 mod = PyImport_ImportModule("mercurial.error");
1373 1375 if (mod == NULL)
1374 1376 goto classfail;
1375 1377
1376 1378 dict = PyModule_GetDict(mod);
1377 1379 if (dict == NULL)
1378 1380 goto classfail;
1379 1381
1380 1382 errclass = PyDict_GetItemString(dict, "RevlogError");
1381 1383 if (errclass == NULL) {
1382 1384 PyErr_SetString(PyExc_SystemError,
1383 1385 "could not find RevlogError");
1384 1386 goto classfail;
1385 1387 }
1386 1388 Py_INCREF(errclass);
1387 1389 Py_DECREF(mod);
1388 1390 }
1389 1391
1390 1392 errobj = PyObject_CallFunction(errclass, NULL);
1391 1393 if (errobj == NULL)
1392 1394 return NULL;
1393 1395 PyErr_SetObject(errclass, errobj);
1394 1396 return errobj;
1395 1397
1396 1398 classfail:
1397 1399 Py_XDECREF(mod);
1398 1400 return NULL;
1399 1401 }
1400 1402
1401 1403 static PyObject *index_getitem(indexObject *self, PyObject *value)
1402 1404 {
1403 1405 char *node;
1404 1406 Py_ssize_t nodelen;
1405 1407 int rev;
1406 1408
1407 1409 if (PyInt_Check(value))
1408 1410 return index_get(self, PyInt_AS_LONG(value));
1409 1411
1410 1412 if (node_check(value, &node, &nodelen) == -1)
1411 1413 return NULL;
1412 1414 rev = index_find_node(self, node, nodelen);
1413 1415 if (rev >= -1)
1414 1416 return PyInt_FromLong(rev);
1415 1417 if (rev == -2)
1416 1418 raise_revlog_error();
1417 1419 return NULL;
1418 1420 }
1419 1421
1420 1422 static int nt_partialmatch(indexObject *self, const char *node,
1421 1423 Py_ssize_t nodelen)
1422 1424 {
1423 1425 int rev;
1424 1426
1425 1427 if (nt_init(self) == -1)
1426 1428 return -3;
1427 1429
1428 1430 if (self->ntrev > 0) {
1429 1431 /* ensure that the radix tree is fully populated */
1430 1432 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1431 1433 const char *n = index_node(self, rev);
1432 1434 if (n == NULL)
1433 1435 return -2;
1434 1436 if (nt_insert(self, n, rev) == -1)
1435 1437 return -3;
1436 1438 }
1437 1439 self->ntrev = rev;
1438 1440 }
1439 1441
1440 1442 return nt_find(self, node, nodelen, 1);
1441 1443 }
1442 1444
1443 1445 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1444 1446 {
1445 1447 const char *fullnode;
1446 1448 int nodelen;
1447 1449 char *node;
1448 1450 int rev, i;
1449 1451
1450 1452 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1451 1453 return NULL;
1452 1454
1453 1455 if (nodelen < 4) {
1454 1456 PyErr_SetString(PyExc_ValueError, "key too short");
1455 1457 return NULL;
1456 1458 }
1457 1459
1458 1460 if (nodelen > 40) {
1459 1461 PyErr_SetString(PyExc_ValueError, "key too long");
1460 1462 return NULL;
1461 1463 }
1462 1464
1463 1465 for (i = 0; i < nodelen; i++)
1464 1466 hexdigit(node, i);
1465 1467 if (PyErr_Occurred()) {
1466 1468 /* input contains non-hex characters */
1467 1469 PyErr_Clear();
1468 1470 Py_RETURN_NONE;
1469 1471 }
1470 1472
1471 1473 rev = nt_partialmatch(self, node, nodelen);
1472 1474
1473 1475 switch (rev) {
1474 1476 case -4:
1475 1477 raise_revlog_error();
1476 1478 case -3:
1477 1479 return NULL;
1478 1480 case -2:
1479 1481 Py_RETURN_NONE;
1480 1482 case -1:
1481 1483 return PyString_FromStringAndSize(nullid, 20);
1482 1484 }
1483 1485
1484 1486 fullnode = index_node(self, rev);
1485 1487 if (fullnode == NULL) {
1486 1488 PyErr_Format(PyExc_IndexError,
1487 1489 "could not access rev %d", rev);
1488 1490 return NULL;
1489 1491 }
1490 1492 return PyString_FromStringAndSize(fullnode, 20);
1491 1493 }
1492 1494
1493 1495 static PyObject *index_m_get(indexObject *self, PyObject *args)
1494 1496 {
1495 1497 Py_ssize_t nodelen;
1496 1498 PyObject *val;
1497 1499 char *node;
1498 1500 int rev;
1499 1501
1500 1502 if (!PyArg_ParseTuple(args, "O", &val))
1501 1503 return NULL;
1502 1504 if (node_check(val, &node, &nodelen) == -1)
1503 1505 return NULL;
1504 1506 rev = index_find_node(self, node, nodelen);
1505 1507 if (rev == -3)
1506 1508 return NULL;
1507 1509 if (rev == -2)
1508 1510 Py_RETURN_NONE;
1509 1511 return PyInt_FromLong(rev);
1510 1512 }
1511 1513
1512 1514 static int index_contains(indexObject *self, PyObject *value)
1513 1515 {
1514 1516 char *node;
1515 1517 Py_ssize_t nodelen;
1516 1518
1517 1519 if (PyInt_Check(value)) {
1518 1520 long rev = PyInt_AS_LONG(value);
1519 1521 return rev >= -1 && rev < index_length(self);
1520 1522 }
1521 1523
1522 1524 if (node_check(value, &node, &nodelen) == -1)
1523 1525 return -1;
1524 1526
1525 1527 switch (index_find_node(self, node, nodelen)) {
1526 1528 case -3:
1527 1529 return -1;
1528 1530 case -2:
1529 1531 return 0;
1530 1532 default:
1531 1533 return 1;
1532 1534 }
1533 1535 }
1534 1536
1535 1537 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1536 1538 {
1537 1539 if (rev >= self->length - 1) {
1538 1540 PyObject *tuple = PyList_GET_ITEM(self->added,
1539 1541 rev - self->length + 1);
1540 1542 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1541 1543 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1542 1544 } else {
1543 1545 const char *data = index_deref(self, rev);
1544 1546 ps[0] = getbe32(data + 24);
1545 1547 ps[1] = getbe32(data + 28);
1546 1548 }
1547 1549 }
1548 1550
1549 1551 typedef uint64_t bitmask;
1550 1552
1551 1553 /*
1552 1554 * Given a disjoint set of revs, return all candidates for the
1553 1555 * greatest common ancestor. In revset notation, this is the set
1554 1556 * "heads(::a and ::b and ...)"
1555 1557 */
1556 1558 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1557 1559 int revcount)
1558 1560 {
1559 1561 const bitmask allseen = (1ull << revcount) - 1;
1560 1562 const bitmask poison = 1ull << revcount;
1561 1563 PyObject *gca = PyList_New(0);
1562 1564 int i, v, interesting;
1563 1565 int maxrev = -1;
1564 1566 bitmask sp;
1565 1567 bitmask *seen;
1566 1568
1567 1569 if (gca == NULL)
1568 1570 return PyErr_NoMemory();
1569 1571
1570 1572 for (i = 0; i < revcount; i++) {
1571 1573 if (revs[i] > maxrev)
1572 1574 maxrev = revs[i];
1573 1575 }
1574 1576
1575 1577 seen = calloc(sizeof(*seen), maxrev + 1);
1576 1578 if (seen == NULL) {
1577 1579 Py_DECREF(gca);
1578 1580 return PyErr_NoMemory();
1579 1581 }
1580 1582
1581 1583 for (i = 0; i < revcount; i++)
1582 1584 seen[revs[i]] = 1ull << i;
1583 1585
1584 1586 interesting = revcount;
1585 1587
1586 1588 for (v = maxrev; v >= 0 && interesting; v--) {
1587 1589 bitmask sv = seen[v];
1588 1590 int parents[2];
1589 1591
1590 1592 if (!sv)
1591 1593 continue;
1592 1594
1593 1595 if (sv < poison) {
1594 1596 interesting -= 1;
1595 1597 if (sv == allseen) {
1596 1598 PyObject *obj = PyInt_FromLong(v);
1597 1599 if (obj == NULL)
1598 1600 goto bail;
1599 1601 if (PyList_Append(gca, obj) == -1) {
1600 1602 Py_DECREF(obj);
1601 1603 goto bail;
1602 1604 }
1603 1605 sv |= poison;
1604 1606 for (i = 0; i < revcount; i++) {
1605 1607 if (revs[i] == v)
1606 1608 goto done;
1607 1609 }
1608 1610 }
1609 1611 }
1610 1612 index_get_parents(self, v, parents);
1611 1613
1612 1614 for (i = 0; i < 2; i++) {
1613 1615 int p = parents[i];
1614 1616 if (p == -1)
1615 1617 continue;
1616 1618 sp = seen[p];
1617 1619 if (sv < poison) {
1618 1620 if (sp == 0) {
1619 1621 seen[p] = sv;
1620 1622 interesting++;
1621 1623 }
1622 1624 else if (sp != sv)
1623 1625 seen[p] |= sv;
1624 1626 } else {
1625 1627 if (sp && sp < poison)
1626 1628 interesting--;
1627 1629 seen[p] = sv;
1628 1630 }
1629 1631 }
1630 1632 }
1631 1633
1632 1634 done:
1633 1635 free(seen);
1634 1636 return gca;
1635 1637 bail:
1636 1638 free(seen);
1637 1639 Py_XDECREF(gca);
1638 1640 return NULL;
1639 1641 }
1640 1642
1641 1643 /*
1642 1644 * Given a disjoint set of revs, return the subset with the longest
1643 1645 * path to the root.
1644 1646 */
1645 1647 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1646 1648 {
1647 1649 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1648 1650 static const Py_ssize_t capacity = 24;
1649 1651 int *depth, *interesting = NULL;
1650 1652 int i, j, v, ninteresting;
1651 1653 PyObject *dict = NULL, *keys = NULL;
1652 1654 long *seen = NULL;
1653 1655 int maxrev = -1;
1654 1656 long final;
1655 1657
1656 1658 if (revcount > capacity) {
1657 1659 PyErr_Format(PyExc_OverflowError,
1658 1660 "bitset size (%ld) > capacity (%ld)",
1659 1661 (long)revcount, (long)capacity);
1660 1662 return NULL;
1661 1663 }
1662 1664
1663 1665 for (i = 0; i < revcount; i++) {
1664 1666 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1665 1667 if (n > maxrev)
1666 1668 maxrev = n;
1667 1669 }
1668 1670
1669 1671 depth = calloc(sizeof(*depth), maxrev + 1);
1670 1672 if (depth == NULL)
1671 1673 return PyErr_NoMemory();
1672 1674
1673 1675 seen = calloc(sizeof(*seen), maxrev + 1);
1674 1676 if (seen == NULL) {
1675 1677 PyErr_NoMemory();
1676 1678 goto bail;
1677 1679 }
1678 1680
1679 1681 interesting = calloc(sizeof(*interesting), 2 << revcount);
1680 1682 if (interesting == NULL) {
1681 1683 PyErr_NoMemory();
1682 1684 goto bail;
1683 1685 }
1684 1686
1685 1687 if (PyList_Sort(revs) == -1)
1686 1688 goto bail;
1687 1689
1688 1690 for (i = 0; i < revcount; i++) {
1689 1691 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1690 1692 long b = 1l << i;
1691 1693 depth[n] = 1;
1692 1694 seen[n] = b;
1693 1695 interesting[b] = 1;
1694 1696 }
1695 1697
1696 1698 ninteresting = (int)revcount;
1697 1699
1698 1700 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1699 1701 int dv = depth[v];
1700 1702 int parents[2];
1701 1703 long sv;
1702 1704
1703 1705 if (dv == 0)
1704 1706 continue;
1705 1707
1706 1708 sv = seen[v];
1707 1709 index_get_parents(self, v, parents);
1708 1710
1709 1711 for (i = 0; i < 2; i++) {
1710 1712 int p = parents[i];
1711 1713 long nsp, sp;
1712 1714 int dp;
1713 1715
1714 1716 if (p == -1)
1715 1717 continue;
1716 1718
1717 1719 dp = depth[p];
1718 1720 nsp = sp = seen[p];
1719 1721 if (dp <= dv) {
1720 1722 depth[p] = dv + 1;
1721 1723 if (sp != sv) {
1722 1724 interesting[sv] += 1;
1723 1725 nsp = seen[p] = sv;
1724 1726 if (sp) {
1725 1727 interesting[sp] -= 1;
1726 1728 if (interesting[sp] == 0)
1727 1729 ninteresting -= 1;
1728 1730 }
1729 1731 }
1730 1732 }
1731 1733 else if (dv == dp - 1) {
1732 1734 nsp = sp | sv;
1733 1735 if (nsp == sp)
1734 1736 continue;
1735 1737 seen[p] = nsp;
1736 1738 interesting[sp] -= 1;
1737 1739 if (interesting[sp] == 0 && interesting[nsp] > 0)
1738 1740 ninteresting -= 1;
1739 1741 interesting[nsp] += 1;
1740 1742 }
1741 1743 }
1742 1744 interesting[sv] -= 1;
1743 1745 if (interesting[sv] == 0)
1744 1746 ninteresting -= 1;
1745 1747 }
1746 1748
1747 1749 final = 0;
1748 1750 j = ninteresting;
1749 1751 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1750 1752 if (interesting[i] == 0)
1751 1753 continue;
1752 1754 final |= i;
1753 1755 j -= 1;
1754 1756 }
1755 1757 if (final == 0) {
1756 1758 keys = PyList_New(0);
1757 1759 goto bail;
1758 1760 }
1759 1761
1760 1762 dict = PyDict_New();
1761 1763 if (dict == NULL)
1762 1764 goto bail;
1763 1765
1764 1766 for (i = 0; i < revcount; i++) {
1765 1767 PyObject *key;
1766 1768
1767 1769 if ((final & (1 << i)) == 0)
1768 1770 continue;
1769 1771
1770 1772 key = PyList_GET_ITEM(revs, i);
1771 1773 Py_INCREF(key);
1772 1774 Py_INCREF(Py_None);
1773 1775 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1774 1776 Py_DECREF(key);
1775 1777 Py_DECREF(Py_None);
1776 1778 goto bail;
1777 1779 }
1778 1780 }
1779 1781
1780 1782 keys = PyDict_Keys(dict);
1781 1783
1782 1784 bail:
1783 1785 free(depth);
1784 1786 free(seen);
1785 1787 free(interesting);
1786 1788 Py_XDECREF(dict);
1787 1789
1788 1790 return keys;
1789 1791 }
1790 1792
1791 1793 /*
1792 1794 * Given a (possibly overlapping) set of revs, return all the
1793 1795 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1794 1796 */
1795 1797 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1796 1798 {
1797 1799 PyObject *ret = NULL;
1798 1800 Py_ssize_t argcount, i, len;
1799 1801 bitmask repeat = 0;
1800 1802 int revcount = 0;
1801 1803 int *revs;
1802 1804
1803 1805 argcount = PySequence_Length(args);
1804 1806 revs = malloc(argcount * sizeof(*revs));
1805 1807 if (argcount > 0 && revs == NULL)
1806 1808 return PyErr_NoMemory();
1807 1809 len = index_length(self) - 1;
1808 1810
1809 1811 for (i = 0; i < argcount; i++) {
1810 1812 static const int capacity = 24;
1811 1813 PyObject *obj = PySequence_GetItem(args, i);
1812 1814 bitmask x;
1813 1815 long val;
1814 1816
1815 1817 if (!PyInt_Check(obj)) {
1816 1818 PyErr_SetString(PyExc_TypeError,
1817 1819 "arguments must all be ints");
1818 1820 Py_DECREF(obj);
1819 1821 goto bail;
1820 1822 }
1821 1823 val = PyInt_AsLong(obj);
1822 1824 Py_DECREF(obj);
1823 1825 if (val == -1) {
1824 1826 ret = PyList_New(0);
1825 1827 goto done;
1826 1828 }
1827 1829 if (val < 0 || val >= len) {
1828 1830 PyErr_SetString(PyExc_IndexError,
1829 1831 "index out of range");
1830 1832 goto bail;
1831 1833 }
1832 1834 /* this cheesy bloom filter lets us avoid some more
1833 1835 * expensive duplicate checks in the common set-is-disjoint
1834 1836 * case */
1835 1837 x = 1ull << (val & 0x3f);
1836 1838 if (repeat & x) {
1837 1839 int k;
1838 1840 for (k = 0; k < revcount; k++) {
1839 1841 if (val == revs[k])
1840 1842 goto duplicate;
1841 1843 }
1842 1844 }
1843 1845 else repeat |= x;
1844 1846 if (revcount >= capacity) {
1845 1847 PyErr_Format(PyExc_OverflowError,
1846 1848 "bitset size (%d) > capacity (%d)",
1847 1849 revcount, capacity);
1848 1850 goto bail;
1849 1851 }
1850 1852 revs[revcount++] = (int)val;
1851 1853 duplicate:;
1852 1854 }
1853 1855
1854 1856 if (revcount == 0) {
1855 1857 ret = PyList_New(0);
1856 1858 goto done;
1857 1859 }
1858 1860 if (revcount == 1) {
1859 1861 PyObject *obj;
1860 1862 ret = PyList_New(1);
1861 1863 if (ret == NULL)
1862 1864 goto bail;
1863 1865 obj = PyInt_FromLong(revs[0]);
1864 1866 if (obj == NULL)
1865 1867 goto bail;
1866 1868 PyList_SET_ITEM(ret, 0, obj);
1867 1869 goto done;
1868 1870 }
1869 1871
1870 1872 ret = find_gca_candidates(self, revs, revcount);
1871 1873 if (ret == NULL)
1872 1874 goto bail;
1873 1875
1874 1876 done:
1875 1877 free(revs);
1876 1878 return ret;
1877 1879
1878 1880 bail:
1879 1881 free(revs);
1880 1882 Py_XDECREF(ret);
1881 1883 return NULL;
1882 1884 }
1883 1885
1884 1886 /*
1885 1887 * Given a (possibly overlapping) set of revs, return the greatest
1886 1888 * common ancestors: those with the longest path to the root.
1887 1889 */
1888 1890 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1889 1891 {
1890 1892 PyObject *gca = index_commonancestorsheads(self, args);
1891 1893 if (gca == NULL)
1892 1894 return NULL;
1893 1895
1894 1896 if (PyList_GET_SIZE(gca) <= 1) {
1895 1897 Py_INCREF(gca);
1896 1898 return gca;
1897 1899 }
1898 1900
1899 1901 return find_deepest(self, gca);
1900 1902 }
1901 1903
1902 1904 /*
1903 1905 * Invalidate any trie entries introduced by added revs.
1904 1906 */
1905 1907 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1906 1908 {
1907 1909 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1908 1910
1909 1911 for (i = start; i < len; i++) {
1910 1912 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1911 1913 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1912 1914
1913 1915 nt_insert(self, PyString_AS_STRING(node), -1);
1914 1916 }
1915 1917
1916 1918 if (start == 0)
1917 1919 Py_CLEAR(self->added);
1918 1920 }
1919 1921
1920 1922 /*
1921 1923 * Delete a numeric range of revs, which must be at the end of the
1922 1924 * range, but exclude the sentinel nullid entry.
1923 1925 */
1924 1926 static int index_slice_del(indexObject *self, PyObject *item)
1925 1927 {
1926 1928 Py_ssize_t start, stop, step, slicelength;
1927 1929 Py_ssize_t length = index_length(self);
1928 1930 int ret = 0;
1929 1931
1930 1932 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1931 1933 &start, &stop, &step, &slicelength) < 0)
1932 1934 return -1;
1933 1935
1934 1936 if (slicelength <= 0)
1935 1937 return 0;
1936 1938
1937 1939 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1938 1940 stop = start;
1939 1941
1940 1942 if (step < 0) {
1941 1943 stop = start + 1;
1942 1944 start = stop + step*(slicelength - 1) - 1;
1943 1945 step = -step;
1944 1946 }
1945 1947
1946 1948 if (step != 1) {
1947 1949 PyErr_SetString(PyExc_ValueError,
1948 1950 "revlog index delete requires step size of 1");
1949 1951 return -1;
1950 1952 }
1951 1953
1952 1954 if (stop != length - 1) {
1953 1955 PyErr_SetString(PyExc_IndexError,
1954 1956 "revlog index deletion indices are invalid");
1955 1957 return -1;
1956 1958 }
1957 1959
1958 1960 if (start < self->length - 1) {
1959 1961 if (self->nt) {
1960 1962 Py_ssize_t i;
1961 1963
1962 1964 for (i = start + 1; i < self->length - 1; i++) {
1963 1965 const char *node = index_node(self, i);
1964 1966
1965 1967 if (node)
1966 1968 nt_insert(self, node, -1);
1967 1969 }
1968 1970 if (self->added)
1969 1971 nt_invalidate_added(self, 0);
1970 1972 if (self->ntrev > start)
1971 1973 self->ntrev = (int)start;
1972 1974 }
1973 1975 self->length = start + 1;
1974 1976 if (start < self->raw_length) {
1975 1977 if (self->cache) {
1976 1978 Py_ssize_t i;
1977 1979 for (i = start; i < self->raw_length; i++)
1978 1980 Py_CLEAR(self->cache[i]);
1979 1981 }
1980 1982 self->raw_length = start;
1981 1983 }
1982 1984 goto done;
1983 1985 }
1984 1986
1985 1987 if (self->nt) {
1986 1988 nt_invalidate_added(self, start - self->length + 1);
1987 1989 if (self->ntrev > start)
1988 1990 self->ntrev = (int)start;
1989 1991 }
1990 1992 if (self->added)
1991 1993 ret = PyList_SetSlice(self->added, start - self->length + 1,
1992 1994 PyList_GET_SIZE(self->added), NULL);
1993 1995 done:
1994 1996 Py_CLEAR(self->headrevs);
1995 1997 return ret;
1996 1998 }
1997 1999
1998 2000 /*
1999 2001 * Supported ops:
2000 2002 *
2001 2003 * slice deletion
2002 2004 * string assignment (extend node->rev mapping)
2003 2005 * string deletion (shrink node->rev mapping)
2004 2006 */
2005 2007 static int index_assign_subscript(indexObject *self, PyObject *item,
2006 2008 PyObject *value)
2007 2009 {
2008 2010 char *node;
2009 2011 Py_ssize_t nodelen;
2010 2012 long rev;
2011 2013
2012 2014 if (PySlice_Check(item) && value == NULL)
2013 2015 return index_slice_del(self, item);
2014 2016
2015 2017 if (node_check(item, &node, &nodelen) == -1)
2016 2018 return -1;
2017 2019
2018 2020 if (value == NULL)
2019 2021 return self->nt ? nt_insert(self, node, -1) : 0;
2020 2022 rev = PyInt_AsLong(value);
2021 2023 if (rev > INT_MAX || rev < 0) {
2022 2024 if (!PyErr_Occurred())
2023 2025 PyErr_SetString(PyExc_ValueError, "rev out of range");
2024 2026 return -1;
2025 2027 }
2026 2028
2027 2029 if (nt_init(self) == -1)
2028 2030 return -1;
2029 2031 return nt_insert(self, node, (int)rev);
2030 2032 }
2031 2033
2032 2034 /*
2033 2035 * Find all RevlogNG entries in an index that has inline data. Update
2034 2036 * the optional "offsets" table with those entries.
2035 2037 */
2036 2038 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2037 2039 {
2038 2040 const char *data = PyString_AS_STRING(self->data);
2039 2041 Py_ssize_t pos = 0;
2040 2042 Py_ssize_t end = PyString_GET_SIZE(self->data);
2041 2043 long incr = v1_hdrsize;
2042 2044 Py_ssize_t len = 0;
2043 2045
2044 2046 while (pos + v1_hdrsize <= end && pos >= 0) {
2045 2047 uint32_t comp_len;
2046 2048 /* 3rd element of header is length of compressed inline data */
2047 2049 comp_len = getbe32(data + pos + 8);
2048 2050 incr = v1_hdrsize + comp_len;
2049 2051 if (offsets)
2050 2052 offsets[len] = data + pos;
2051 2053 len++;
2052 2054 pos += incr;
2053 2055 }
2054 2056
2055 2057 if (pos != end) {
2056 2058 if (!PyErr_Occurred())
2057 2059 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2058 2060 return -1;
2059 2061 }
2060 2062
2061 2063 return len;
2062 2064 }
2063 2065
2064 2066 static int index_init(indexObject *self, PyObject *args)
2065 2067 {
2066 2068 PyObject *data_obj, *inlined_obj;
2067 2069 Py_ssize_t size;
2068 2070
2069 2071 /* Initialize before argument-checking to avoid index_dealloc() crash. */
2070 2072 self->raw_length = 0;
2071 2073 self->added = NULL;
2072 2074 self->cache = NULL;
2073 2075 self->data = NULL;
2074 2076 self->headrevs = NULL;
2075 2077 self->filteredrevs = Py_None;
2076 2078 Py_INCREF(Py_None);
2077 2079 self->nt = NULL;
2078 2080 self->offsets = NULL;
2079 2081
2080 2082 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2081 2083 return -1;
2082 2084 if (!PyString_Check(data_obj)) {
2083 2085 PyErr_SetString(PyExc_TypeError, "data is not a string");
2084 2086 return -1;
2085 2087 }
2086 2088 size = PyString_GET_SIZE(data_obj);
2087 2089
2088 2090 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2089 2091 self->data = data_obj;
2090 2092
2091 2093 self->ntlength = self->ntcapacity = 0;
2092 2094 self->ntdepth = self->ntsplits = 0;
2093 2095 self->ntlookups = self->ntmisses = 0;
2094 2096 self->ntrev = -1;
2095 2097 Py_INCREF(self->data);
2096 2098
2097 2099 if (self->inlined) {
2098 2100 Py_ssize_t len = inline_scan(self, NULL);
2099 2101 if (len == -1)
2100 2102 goto bail;
2101 2103 self->raw_length = len;
2102 2104 self->length = len + 1;
2103 2105 } else {
2104 2106 if (size % v1_hdrsize) {
2105 2107 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2106 2108 goto bail;
2107 2109 }
2108 2110 self->raw_length = size / v1_hdrsize;
2109 2111 self->length = self->raw_length + 1;
2110 2112 }
2111 2113
2112 2114 return 0;
2113 2115 bail:
2114 2116 return -1;
2115 2117 }
2116 2118
2117 2119 static PyObject *index_nodemap(indexObject *self)
2118 2120 {
2119 2121 Py_INCREF(self);
2120 2122 return (PyObject *)self;
2121 2123 }
2122 2124
2123 2125 static void index_dealloc(indexObject *self)
2124 2126 {
2125 2127 _index_clearcaches(self);
2126 2128 Py_XDECREF(self->filteredrevs);
2127 2129 Py_XDECREF(self->data);
2128 2130 Py_XDECREF(self->added);
2129 2131 PyObject_Del(self);
2130 2132 }
2131 2133
2132 2134 static PySequenceMethods index_sequence_methods = {
2133 2135 (lenfunc)index_length, /* sq_length */
2134 2136 0, /* sq_concat */
2135 2137 0, /* sq_repeat */
2136 2138 (ssizeargfunc)index_get, /* sq_item */
2137 2139 0, /* sq_slice */
2138 2140 0, /* sq_ass_item */
2139 2141 0, /* sq_ass_slice */
2140 2142 (objobjproc)index_contains, /* sq_contains */
2141 2143 };
2142 2144
2143 2145 static PyMappingMethods index_mapping_methods = {
2144 2146 (lenfunc)index_length, /* mp_length */
2145 2147 (binaryfunc)index_getitem, /* mp_subscript */
2146 2148 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2147 2149 };
2148 2150
2149 2151 static PyMethodDef index_methods[] = {
2150 2152 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2151 2153 "return the gca set of the given revs"},
2152 2154 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2153 2155 METH_VARARGS,
2154 2156 "return the heads of the common ancestors of the given revs"},
2155 2157 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2156 2158 "clear the index caches"},
2157 2159 {"get", (PyCFunction)index_m_get, METH_VARARGS,
2158 2160 "get an index entry"},
2159 2161 {"computephases", (PyCFunction)compute_phases, METH_VARARGS,
2160 2162 "compute phases"},
2161 2163 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2162 2164 "get head revisions"}, /* Can do filtering since 3.2 */
2163 2165 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2164 2166 "get filtered head revisions"}, /* Can always do filtering */
2165 2167 {"insert", (PyCFunction)index_insert, METH_VARARGS,
2166 2168 "insert an index entry"},
2167 2169 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2168 2170 "match a potentially ambiguous node ID"},
2169 2171 {"stats", (PyCFunction)index_stats, METH_NOARGS,
2170 2172 "stats for the index"},
2171 2173 {NULL} /* Sentinel */
2172 2174 };
2173 2175
2174 2176 static PyGetSetDef index_getset[] = {
2175 2177 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2176 2178 {NULL} /* Sentinel */
2177 2179 };
2178 2180
2179 2181 static PyTypeObject indexType = {
2180 2182 PyObject_HEAD_INIT(NULL)
2181 2183 0, /* ob_size */
2182 2184 "parsers.index", /* tp_name */
2183 2185 sizeof(indexObject), /* tp_basicsize */
2184 2186 0, /* tp_itemsize */
2185 2187 (destructor)index_dealloc, /* tp_dealloc */
2186 2188 0, /* tp_print */
2187 2189 0, /* tp_getattr */
2188 2190 0, /* tp_setattr */
2189 2191 0, /* tp_compare */
2190 2192 0, /* tp_repr */
2191 2193 0, /* tp_as_number */
2192 2194 &index_sequence_methods, /* tp_as_sequence */
2193 2195 &index_mapping_methods, /* tp_as_mapping */
2194 2196 0, /* tp_hash */
2195 2197 0, /* tp_call */
2196 2198 0, /* tp_str */
2197 2199 0, /* tp_getattro */
2198 2200 0, /* tp_setattro */
2199 2201 0, /* tp_as_buffer */
2200 2202 Py_TPFLAGS_DEFAULT, /* tp_flags */
2201 2203 "revlog index", /* tp_doc */
2202 2204 0, /* tp_traverse */
2203 2205 0, /* tp_clear */
2204 2206 0, /* tp_richcompare */
2205 2207 0, /* tp_weaklistoffset */
2206 2208 0, /* tp_iter */
2207 2209 0, /* tp_iternext */
2208 2210 index_methods, /* tp_methods */
2209 2211 0, /* tp_members */
2210 2212 index_getset, /* tp_getset */
2211 2213 0, /* tp_base */
2212 2214 0, /* tp_dict */
2213 2215 0, /* tp_descr_get */
2214 2216 0, /* tp_descr_set */
2215 2217 0, /* tp_dictoffset */
2216 2218 (initproc)index_init, /* tp_init */
2217 2219 0, /* tp_alloc */
2218 2220 };
2219 2221
2220 2222 /*
2221 2223 * returns a tuple of the form (index, index, cache) with elements as
2222 2224 * follows:
2223 2225 *
2224 2226 * index: an index object that lazily parses RevlogNG records
2225 2227 * cache: if data is inlined, a tuple (index_file_content, 0), else None
2226 2228 *
2227 2229 * added complications are for backwards compatibility
2228 2230 */
2229 2231 static PyObject *parse_index2(PyObject *self, PyObject *args)
2230 2232 {
2231 2233 PyObject *tuple = NULL, *cache = NULL;
2232 2234 indexObject *idx;
2233 2235 int ret;
2234 2236
2235 2237 idx = PyObject_New(indexObject, &indexType);
2236 2238 if (idx == NULL)
2237 2239 goto bail;
2238 2240
2239 2241 ret = index_init(idx, args);
2240 2242 if (ret == -1)
2241 2243 goto bail;
2242 2244
2243 2245 if (idx->inlined) {
2244 2246 cache = Py_BuildValue("iO", 0, idx->data);
2245 2247 if (cache == NULL)
2246 2248 goto bail;
2247 2249 } else {
2248 2250 cache = Py_None;
2249 2251 Py_INCREF(cache);
2250 2252 }
2251 2253
2252 2254 tuple = Py_BuildValue("NN", idx, cache);
2253 2255 if (!tuple)
2254 2256 goto bail;
2255 2257 return tuple;
2256 2258
2257 2259 bail:
2258 2260 Py_XDECREF(idx);
2259 2261 Py_XDECREF(cache);
2260 2262 Py_XDECREF(tuple);
2261 2263 return NULL;
2262 2264 }
2263 2265
2264 2266 #define BUMPED_FIX 1
2265 2267 #define USING_SHA_256 2
2266 2268
2267 2269 static PyObject *readshas(
2268 2270 const char *source, unsigned char num, Py_ssize_t hashwidth)
2269 2271 {
2270 2272 int i;
2271 2273 PyObject *list = PyTuple_New(num);
2272 2274 if (list == NULL) {
2273 2275 return NULL;
2274 2276 }
2275 2277 for (i = 0; i < num; i++) {
2276 2278 PyObject *hash = PyString_FromStringAndSize(source, hashwidth);
2277 2279 if (hash == NULL) {
2278 2280 Py_DECREF(list);
2279 2281 return NULL;
2280 2282 }
2281 2283 PyTuple_SetItem(list, i, hash);
2282 2284 source += hashwidth;
2283 2285 }
2284 2286 return list;
2285 2287 }
2286 2288
2287 2289 static PyObject *fm1readmarker(const char *data, uint32_t *msize)
2288 2290 {
2289 2291 const char *meta;
2290 2292
2291 2293 double mtime;
2292 2294 int16_t tz;
2293 2295 uint16_t flags;
2294 2296 unsigned char nsuccs, nparents, nmetadata;
2295 2297 Py_ssize_t hashwidth = 20;
2296 2298
2297 2299 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
2298 2300 PyObject *metadata = NULL, *ret = NULL;
2299 2301 int i;
2300 2302
2301 2303 *msize = getbe32(data);
2302 2304 data += 4;
2303 2305 mtime = getbefloat64(data);
2304 2306 data += 8;
2305 2307 tz = getbeint16(data);
2306 2308 data += 2;
2307 2309 flags = getbeuint16(data);
2308 2310 data += 2;
2309 2311
2310 2312 if (flags & USING_SHA_256) {
2311 2313 hashwidth = 32;
2312 2314 }
2313 2315
2314 2316 nsuccs = (unsigned char)(*data++);
2315 2317 nparents = (unsigned char)(*data++);
2316 2318 nmetadata = (unsigned char)(*data++);
2317 2319
2318 2320 prec = PyString_FromStringAndSize(data, hashwidth);
2319 2321 data += hashwidth;
2320 2322 if (prec == NULL) {
2321 2323 goto bail;
2322 2324 }
2323 2325
2324 2326 succs = readshas(data, nsuccs, hashwidth);
2325 2327 if (succs == NULL) {
2326 2328 goto bail;
2327 2329 }
2328 2330 data += nsuccs * hashwidth;
2329 2331
2330 2332 if (nparents == 1 || nparents == 2) {
2331 2333 parents = readshas(data, nparents, hashwidth);
2332 2334 if (parents == NULL) {
2333 2335 goto bail;
2334 2336 }
2335 2337 data += nparents * hashwidth;
2336 2338 } else {
2337 2339 parents = Py_None;
2338 2340 }
2339 2341
2340 2342 meta = data + (2 * nmetadata);
2341 2343 metadata = PyTuple_New(nmetadata);
2342 2344 if (metadata == NULL) {
2343 2345 goto bail;
2344 2346 }
2345 2347 for (i = 0; i < nmetadata; i++) {
2346 2348 PyObject *tmp, *left = NULL, *right = NULL;
2347 2349 Py_ssize_t metasize = (unsigned char)(*data++);
2348 2350 left = PyString_FromStringAndSize(meta, metasize);
2349 2351 meta += metasize;
2350 2352 metasize = (unsigned char)(*data++);
2351 2353 right = PyString_FromStringAndSize(meta, metasize);
2352 2354 meta += metasize;
2353 2355 if (!left || !right) {
2354 2356 Py_XDECREF(left);
2355 2357 Py_XDECREF(right);
2356 2358 goto bail;
2357 2359 }
2358 2360 tmp = PyTuple_Pack(2, left, right);
2359 2361 Py_DECREF(left);
2360 2362 Py_DECREF(right);
2361 2363 if (!tmp) {
2362 2364 goto bail;
2363 2365 }
2364 2366 PyTuple_SetItem(metadata, i, tmp);
2365 2367 }
2366 2368 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags,
2367 2369 metadata, mtime, (int)tz * 60, parents);
2368 2370 bail:
2369 2371 Py_XDECREF(prec);
2370 2372 Py_XDECREF(succs);
2371 2373 Py_XDECREF(metadata);
2372 2374 if (parents != Py_None)
2373 2375 Py_XDECREF(parents);
2374 2376 return ret;
2375 2377 }
2376 2378
2377 2379
2378 2380 static PyObject *fm1readmarkers(PyObject *self, PyObject *args) {
2379 2381 const char *data;
2380 2382 Py_ssize_t datalen;
2381 2383 /* only unsigned long because python 2.4, should be Py_ssize_t */
2382 2384 unsigned long offset, stop;
2383 2385 PyObject *markers = NULL;
2384 2386
2385 2387 /* replace kk with nn when we drop Python 2.4 */
2386 2388 if (!PyArg_ParseTuple(args, "s#kk", &data, &datalen, &offset, &stop)) {
2387 2389 return NULL;
2388 2390 }
2389 2391 data += offset;
2390 2392 markers = PyList_New(0);
2391 2393 if (!markers) {
2392 2394 return NULL;
2393 2395 }
2394 2396 while (offset < stop) {
2395 2397 uint32_t msize;
2396 2398 int error;
2397 2399 PyObject *record = fm1readmarker(data, &msize);
2398 2400 if (!record) {
2399 2401 goto bail;
2400 2402 }
2401 2403 error = PyList_Append(markers, record);
2402 2404 Py_DECREF(record);
2403 2405 if (error) {
2404 2406 goto bail;
2405 2407 }
2406 2408 data += msize;
2407 2409 offset += msize;
2408 2410 }
2409 2411 return markers;
2410 2412 bail:
2411 2413 Py_DECREF(markers);
2412 2414 return NULL;
2413 2415 }
2414 2416
2415 2417 static char parsers_doc[] = "Efficient content parsing.";
2416 2418
2417 2419 PyObject *encodedir(PyObject *self, PyObject *args);
2418 2420 PyObject *pathencode(PyObject *self, PyObject *args);
2419 2421 PyObject *lowerencode(PyObject *self, PyObject *args);
2420 2422
2421 2423 static PyMethodDef methods[] = {
2422 2424 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
2423 2425 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2424 2426 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2425 2427 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2426 2428 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
2427 2429 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2428 2430 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2429 2431 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2430 2432 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
2431 2433 "parse v1 obsolete markers\n"},
2432 2434 {NULL, NULL}
2433 2435 };
2434 2436
2435 2437 void dirs_module_init(PyObject *mod);
2436 2438 void manifest_module_init(PyObject *mod);
2437 2439
2438 2440 static void module_init(PyObject *mod)
2439 2441 {
2440 2442 /* This module constant has two purposes. First, it lets us unit test
2441 2443 * the ImportError raised without hard-coding any error text. This
2442 2444 * means we can change the text in the future without breaking tests,
2443 2445 * even across changesets without a recompile. Second, its presence
2444 2446 * can be used to determine whether the version-checking logic is
2445 2447 * present, which also helps in testing across changesets without a
2446 2448 * recompile. Note that this means the pure-Python version of parsers
2447 2449 * should not have this module constant. */
2448 2450 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2449 2451
2450 2452 dirs_module_init(mod);
2451 2453 manifest_module_init(mod);
2452 2454
2453 2455 indexType.tp_new = PyType_GenericNew;
2454 2456 if (PyType_Ready(&indexType) < 0 ||
2455 2457 PyType_Ready(&dirstateTupleType) < 0)
2456 2458 return;
2457 2459 Py_INCREF(&indexType);
2458 2460 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2459 2461 Py_INCREF(&dirstateTupleType);
2460 2462 PyModule_AddObject(mod, "dirstatetuple",
2461 2463 (PyObject *)&dirstateTupleType);
2462 2464
2463 2465 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2464 2466 -1, -1, -1, -1, nullid, 20);
2465 2467 if (nullentry)
2466 2468 PyObject_GC_UnTrack(nullentry);
2467 2469 }
2468 2470
2469 2471 static int check_python_version(void)
2470 2472 {
2471 2473 PyObject *sys = PyImport_ImportModule("sys"), *ver;
2472 2474 long hexversion;
2473 2475 if (!sys)
2474 2476 return -1;
2475 2477 ver = PyObject_GetAttrString(sys, "hexversion");
2476 2478 Py_DECREF(sys);
2477 2479 if (!ver)
2478 2480 return -1;
2479 2481 hexversion = PyInt_AsLong(ver);
2480 2482 Py_DECREF(ver);
2481 2483 /* sys.hexversion is a 32-bit number by default, so the -1 case
2482 2484 * should only occur in unusual circumstances (e.g. if sys.hexversion
2483 2485 * is manually set to an invalid value). */
2484 2486 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2485 2487 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2486 2488 "modules were compiled with Python " PY_VERSION ", but "
2487 2489 "Mercurial is currently using Python with sys.hexversion=%ld: "
2488 2490 "Python %s\n at: %s", versionerrortext, hexversion,
2489 2491 Py_GetVersion(), Py_GetProgramFullPath());
2490 2492 return -1;
2491 2493 }
2492 2494 return 0;
2493 2495 }
2494 2496
2495 2497 #ifdef IS_PY3K
2496 2498 static struct PyModuleDef parsers_module = {
2497 2499 PyModuleDef_HEAD_INIT,
2498 2500 "parsers",
2499 2501 parsers_doc,
2500 2502 -1,
2501 2503 methods
2502 2504 };
2503 2505
2504 2506 PyMODINIT_FUNC PyInit_parsers(void)
2505 2507 {
2506 2508 PyObject *mod;
2507 2509
2508 2510 if (check_python_version() == -1)
2509 2511 return;
2510 2512 mod = PyModule_Create(&parsers_module);
2511 2513 module_init(mod);
2512 2514 return mod;
2513 2515 }
2514 2516 #else
2515 2517 PyMODINIT_FUNC initparsers(void)
2516 2518 {
2517 2519 PyObject *mod;
2518 2520
2519 2521 if (check_python_version() == -1)
2520 2522 return;
2521 2523 mod = Py_InitModule3("parsers", methods, parsers_doc);
2522 2524 module_init(mod);
2523 2525 }
2524 2526 #endif
General Comments 0
You need to be logged in to leave comments. Login now