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