##// END OF EJS Templates
cext: mark constant variables
Yuya Nishihara -
r32385:7640584e default
parent child Browse files
Show More
@@ -1,1009 +1,1009 b''
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 #include "bitmanipulation.h"
17 17
18 18 #ifdef IS_PY3K
19 19 /* The mapping of Python types is meant to be temporary to get Python
20 20 * 3 to compile. We should remove this once Python 3 support is fully
21 21 * supported and proper types are used in the extensions themselves. */
22 22 #define PyInt_Type PyLong_Type
23 23 #define PyInt_Check PyLong_Check
24 24 #define PyInt_FromLong PyLong_FromLong
25 25 #define PyInt_FromSsize_t PyLong_FromSsize_t
26 26 #define PyInt_AS_LONG PyLong_AS_LONG
27 27 #define PyInt_AsLong PyLong_AsLong
28 28 #endif
29 29
30 static char *versionerrortext = "Python minor version mismatch";
30 static const char *const versionerrortext = "Python minor version mismatch";
31 31
32 static char lowertable[128] = {
32 static const char lowertable[128] = {
33 33 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
34 34 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
35 35 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
36 36 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
37 37 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
38 38 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
39 39 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
40 40 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
41 41 '\x40',
42 42 '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', /* A-G */
43 43 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', /* H-O */
44 44 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', /* P-W */
45 45 '\x78', '\x79', '\x7a', /* X-Z */
46 46 '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
47 47 '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
48 48 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
49 49 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
50 50 '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
51 51 };
52 52
53 static char uppertable[128] = {
53 static const char uppertable[128] = {
54 54 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
55 55 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
56 56 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
57 57 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
58 58 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
59 59 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
60 60 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
61 61 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
62 62 '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
63 63 '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f',
64 64 '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
65 65 '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
66 66 '\x60',
67 67 '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', /* a-g */
68 68 '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f', /* h-o */
69 69 '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57', /* p-w */
70 70 '\x58', '\x59', '\x5a', /* x-z */
71 71 '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
72 72 };
73 73
74 74 /*
75 75 * Turn a hex-encoded string into binary.
76 76 */
77 77 PyObject *unhexlify(const char *str, int len)
78 78 {
79 79 PyObject *ret;
80 80 char *d;
81 81 int i;
82 82
83 83 ret = PyBytes_FromStringAndSize(NULL, len / 2);
84 84
85 85 if (!ret)
86 86 return NULL;
87 87
88 88 d = PyBytes_AsString(ret);
89 89
90 90 for (i = 0; i < len;) {
91 91 int hi = hexdigit(str, i++);
92 92 int lo = hexdigit(str, i++);
93 93 *d++ = (hi << 4) | lo;
94 94 }
95 95
96 96 return ret;
97 97 }
98 98
99 99 static inline PyObject *_asciitransform(PyObject *str_obj,
100 100 const char table[128],
101 101 PyObject *fallback_fn)
102 102 {
103 103 char *str, *newstr;
104 104 Py_ssize_t i, len;
105 105 PyObject *newobj = NULL;
106 106 PyObject *ret = NULL;
107 107
108 108 str = PyBytes_AS_STRING(str_obj);
109 109 len = PyBytes_GET_SIZE(str_obj);
110 110
111 111 newobj = PyBytes_FromStringAndSize(NULL, len);
112 112 if (!newobj)
113 113 goto quit;
114 114
115 115 newstr = PyBytes_AS_STRING(newobj);
116 116
117 117 for (i = 0; i < len; i++) {
118 118 char c = str[i];
119 119 if (c & 0x80) {
120 120 if (fallback_fn != NULL) {
121 121 ret = PyObject_CallFunctionObjArgs(fallback_fn,
122 122 str_obj, NULL);
123 123 } else {
124 124 PyObject *err = PyUnicodeDecodeError_Create(
125 125 "ascii", str, len, i, (i + 1),
126 126 "unexpected code byte");
127 127 PyErr_SetObject(PyExc_UnicodeDecodeError, err);
128 128 Py_XDECREF(err);
129 129 }
130 130 goto quit;
131 131 }
132 132 newstr[i] = table[(unsigned char)c];
133 133 }
134 134
135 135 ret = newobj;
136 136 Py_INCREF(ret);
137 137 quit:
138 138 Py_XDECREF(newobj);
139 139 return ret;
140 140 }
141 141
142 142 static PyObject *asciilower(PyObject *self, PyObject *args)
143 143 {
144 144 PyObject *str_obj;
145 145 if (!PyArg_ParseTuple(args, "O!:asciilower", &PyBytes_Type, &str_obj))
146 146 return NULL;
147 147 return _asciitransform(str_obj, lowertable, NULL);
148 148 }
149 149
150 150 static PyObject *asciiupper(PyObject *self, PyObject *args)
151 151 {
152 152 PyObject *str_obj;
153 153 if (!PyArg_ParseTuple(args, "O!:asciiupper", &PyBytes_Type, &str_obj))
154 154 return NULL;
155 155 return _asciitransform(str_obj, uppertable, NULL);
156 156 }
157 157
158 158 static inline PyObject *_dict_new_presized(Py_ssize_t expected_size)
159 159 {
160 160 /* _PyDict_NewPresized expects a minused parameter, but it actually
161 161 creates a dictionary that's the nearest power of two bigger than the
162 162 parameter. For example, with the initial minused = 1000, the
163 163 dictionary created has size 1024. Of course in a lot of cases that
164 164 can be greater than the maximum load factor Python's dict object
165 165 expects (= 2/3), so as soon as we cross the threshold we'll resize
166 166 anyway. So create a dictionary that's at least 3/2 the size. */
167 167 return _PyDict_NewPresized(((1 + expected_size) / 2) * 3);
168 168 }
169 169
170 170 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
171 171 {
172 172 Py_ssize_t expected_size;
173 173
174 174 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size))
175 175 return NULL;
176 176
177 177 return _dict_new_presized(expected_size);
178 178 }
179 179
180 180 static PyObject *make_file_foldmap(PyObject *self, PyObject *args)
181 181 {
182 182 PyObject *dmap, *spec_obj, *normcase_fallback;
183 183 PyObject *file_foldmap = NULL;
184 184 enum normcase_spec spec;
185 185 PyObject *k, *v;
186 186 dirstateTupleObject *tuple;
187 187 Py_ssize_t pos = 0;
188 188 const char *table;
189 189
190 190 if (!PyArg_ParseTuple(args, "O!O!O!:make_file_foldmap",
191 191 &PyDict_Type, &dmap,
192 192 &PyInt_Type, &spec_obj,
193 193 &PyFunction_Type, &normcase_fallback))
194 194 goto quit;
195 195
196 196 spec = (int)PyInt_AS_LONG(spec_obj);
197 197 switch (spec) {
198 198 case NORMCASE_LOWER:
199 199 table = lowertable;
200 200 break;
201 201 case NORMCASE_UPPER:
202 202 table = uppertable;
203 203 break;
204 204 case NORMCASE_OTHER:
205 205 table = NULL;
206 206 break;
207 207 default:
208 208 PyErr_SetString(PyExc_TypeError, "invalid normcasespec");
209 209 goto quit;
210 210 }
211 211
212 212 /* Add some more entries to deal with additions outside this
213 213 function. */
214 214 file_foldmap = _dict_new_presized((PyDict_Size(dmap) / 10) * 11);
215 215 if (file_foldmap == NULL)
216 216 goto quit;
217 217
218 218 while (PyDict_Next(dmap, &pos, &k, &v)) {
219 219 if (!dirstate_tuple_check(v)) {
220 220 PyErr_SetString(PyExc_TypeError,
221 221 "expected a dirstate tuple");
222 222 goto quit;
223 223 }
224 224
225 225 tuple = (dirstateTupleObject *)v;
226 226 if (tuple->state != 'r') {
227 227 PyObject *normed;
228 228 if (table != NULL) {
229 229 normed = _asciitransform(k, table,
230 230 normcase_fallback);
231 231 } else {
232 232 normed = PyObject_CallFunctionObjArgs(
233 233 normcase_fallback, k, NULL);
234 234 }
235 235
236 236 if (normed == NULL)
237 237 goto quit;
238 238 if (PyDict_SetItem(file_foldmap, normed, k) == -1) {
239 239 Py_DECREF(normed);
240 240 goto quit;
241 241 }
242 242 Py_DECREF(normed);
243 243 }
244 244 }
245 245 return file_foldmap;
246 246 quit:
247 247 Py_XDECREF(file_foldmap);
248 248 return NULL;
249 249 }
250 250
251 251 /*
252 252 * This code assumes that a manifest is stitched together with newline
253 253 * ('\n') characters.
254 254 */
255 255 static PyObject *parse_manifest(PyObject *self, PyObject *args)
256 256 {
257 257 PyObject *mfdict, *fdict;
258 258 char *str, *start, *end;
259 259 int len;
260 260
261 261 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
262 262 &PyDict_Type, &mfdict,
263 263 &PyDict_Type, &fdict,
264 264 &str, &len))
265 265 goto quit;
266 266
267 267 start = str;
268 268 end = str + len;
269 269 while (start < end) {
270 270 PyObject *file = NULL, *node = NULL;
271 271 PyObject *flags = NULL;
272 272 char *zero = NULL, *newline = NULL;
273 273 ptrdiff_t nlen;
274 274
275 275 zero = memchr(start, '\0', end - start);
276 276 if (!zero) {
277 277 PyErr_SetString(PyExc_ValueError,
278 278 "manifest entry has no separator");
279 279 goto quit;
280 280 }
281 281
282 282 newline = memchr(zero + 1, '\n', end - (zero + 1));
283 283 if (!newline) {
284 284 PyErr_SetString(PyExc_ValueError,
285 285 "manifest contains trailing garbage");
286 286 goto quit;
287 287 }
288 288
289 289 file = PyBytes_FromStringAndSize(start, zero - start);
290 290
291 291 if (!file)
292 292 goto bail;
293 293
294 294 nlen = newline - zero - 1;
295 295
296 296 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
297 297 if (!node)
298 298 goto bail;
299 299
300 300 if (nlen > 40) {
301 301 flags = PyBytes_FromStringAndSize(zero + 41,
302 302 nlen - 40);
303 303 if (!flags)
304 304 goto bail;
305 305
306 306 if (PyDict_SetItem(fdict, file, flags) == -1)
307 307 goto bail;
308 308 }
309 309
310 310 if (PyDict_SetItem(mfdict, file, node) == -1)
311 311 goto bail;
312 312
313 313 start = newline + 1;
314 314
315 315 Py_XDECREF(flags);
316 316 Py_XDECREF(node);
317 317 Py_XDECREF(file);
318 318 continue;
319 319 bail:
320 320 Py_XDECREF(flags);
321 321 Py_XDECREF(node);
322 322 Py_XDECREF(file);
323 323 goto quit;
324 324 }
325 325
326 326 Py_INCREF(Py_None);
327 327 return Py_None;
328 328 quit:
329 329 return NULL;
330 330 }
331 331
332 332 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
333 333 int size, int mtime)
334 334 {
335 335 dirstateTupleObject *t = PyObject_New(dirstateTupleObject,
336 336 &dirstateTupleType);
337 337 if (!t)
338 338 return NULL;
339 339 t->state = state;
340 340 t->mode = mode;
341 341 t->size = size;
342 342 t->mtime = mtime;
343 343 return t;
344 344 }
345 345
346 346 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
347 347 PyObject *kwds)
348 348 {
349 349 /* We do all the initialization here and not a tp_init function because
350 350 * dirstate_tuple is immutable. */
351 351 dirstateTupleObject *t;
352 352 char state;
353 353 int size, mode, mtime;
354 354 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
355 355 return NULL;
356 356
357 357 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
358 358 if (!t)
359 359 return NULL;
360 360 t->state = state;
361 361 t->mode = mode;
362 362 t->size = size;
363 363 t->mtime = mtime;
364 364
365 365 return (PyObject *)t;
366 366 }
367 367
368 368 static void dirstate_tuple_dealloc(PyObject *o)
369 369 {
370 370 PyObject_Del(o);
371 371 }
372 372
373 373 static Py_ssize_t dirstate_tuple_length(PyObject *o)
374 374 {
375 375 return 4;
376 376 }
377 377
378 378 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
379 379 {
380 380 dirstateTupleObject *t = (dirstateTupleObject *)o;
381 381 switch (i) {
382 382 case 0:
383 383 return PyBytes_FromStringAndSize(&t->state, 1);
384 384 case 1:
385 385 return PyInt_FromLong(t->mode);
386 386 case 2:
387 387 return PyInt_FromLong(t->size);
388 388 case 3:
389 389 return PyInt_FromLong(t->mtime);
390 390 default:
391 391 PyErr_SetString(PyExc_IndexError, "index out of range");
392 392 return NULL;
393 393 }
394 394 }
395 395
396 396 static PySequenceMethods dirstate_tuple_sq = {
397 397 dirstate_tuple_length, /* sq_length */
398 398 0, /* sq_concat */
399 399 0, /* sq_repeat */
400 400 dirstate_tuple_item, /* sq_item */
401 401 0, /* sq_ass_item */
402 402 0, /* sq_contains */
403 403 0, /* sq_inplace_concat */
404 404 0 /* sq_inplace_repeat */
405 405 };
406 406
407 407 PyTypeObject dirstateTupleType = {
408 408 PyVarObject_HEAD_INIT(NULL, 0)
409 409 "dirstate_tuple", /* tp_name */
410 410 sizeof(dirstateTupleObject),/* tp_basicsize */
411 411 0, /* tp_itemsize */
412 412 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
413 413 0, /* tp_print */
414 414 0, /* tp_getattr */
415 415 0, /* tp_setattr */
416 416 0, /* tp_compare */
417 417 0, /* tp_repr */
418 418 0, /* tp_as_number */
419 419 &dirstate_tuple_sq, /* tp_as_sequence */
420 420 0, /* tp_as_mapping */
421 421 0, /* tp_hash */
422 422 0, /* tp_call */
423 423 0, /* tp_str */
424 424 0, /* tp_getattro */
425 425 0, /* tp_setattro */
426 426 0, /* tp_as_buffer */
427 427 Py_TPFLAGS_DEFAULT, /* tp_flags */
428 428 "dirstate tuple", /* tp_doc */
429 429 0, /* tp_traverse */
430 430 0, /* tp_clear */
431 431 0, /* tp_richcompare */
432 432 0, /* tp_weaklistoffset */
433 433 0, /* tp_iter */
434 434 0, /* tp_iternext */
435 435 0, /* tp_methods */
436 436 0, /* tp_members */
437 437 0, /* tp_getset */
438 438 0, /* tp_base */
439 439 0, /* tp_dict */
440 440 0, /* tp_descr_get */
441 441 0, /* tp_descr_set */
442 442 0, /* tp_dictoffset */
443 443 0, /* tp_init */
444 444 0, /* tp_alloc */
445 445 dirstate_tuple_new, /* tp_new */
446 446 };
447 447
448 448 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
449 449 {
450 450 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
451 451 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
452 452 char state, *cur, *str, *cpos;
453 453 int mode, size, mtime;
454 454 unsigned int flen, len, pos = 40;
455 455 int readlen;
456 456
457 457 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
458 458 &PyDict_Type, &dmap,
459 459 &PyDict_Type, &cmap,
460 460 &str, &readlen))
461 461 goto quit;
462 462
463 463 len = readlen;
464 464
465 465 /* read parents */
466 466 if (len < 40) {
467 467 PyErr_SetString(
468 468 PyExc_ValueError, "too little data for parents");
469 469 goto quit;
470 470 }
471 471
472 472 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
473 473 if (!parents)
474 474 goto quit;
475 475
476 476 /* read filenames */
477 477 while (pos >= 40 && pos < len) {
478 478 if (pos + 17 > len) {
479 479 PyErr_SetString(PyExc_ValueError,
480 480 "overflow in dirstate");
481 481 goto quit;
482 482 }
483 483 cur = str + pos;
484 484 /* unpack header */
485 485 state = *cur;
486 486 mode = getbe32(cur + 1);
487 487 size = getbe32(cur + 5);
488 488 mtime = getbe32(cur + 9);
489 489 flen = getbe32(cur + 13);
490 490 pos += 17;
491 491 cur += 17;
492 492 if (flen > len - pos) {
493 493 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
494 494 goto quit;
495 495 }
496 496
497 497 entry = (PyObject *)make_dirstate_tuple(state, mode, size,
498 498 mtime);
499 499 cpos = memchr(cur, 0, flen);
500 500 if (cpos) {
501 501 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
502 502 cname = PyBytes_FromStringAndSize(cpos + 1,
503 503 flen - (cpos - cur) - 1);
504 504 if (!fname || !cname ||
505 505 PyDict_SetItem(cmap, fname, cname) == -1 ||
506 506 PyDict_SetItem(dmap, fname, entry) == -1)
507 507 goto quit;
508 508 Py_DECREF(cname);
509 509 } else {
510 510 fname = PyBytes_FromStringAndSize(cur, flen);
511 511 if (!fname ||
512 512 PyDict_SetItem(dmap, fname, entry) == -1)
513 513 goto quit;
514 514 }
515 515 Py_DECREF(fname);
516 516 Py_DECREF(entry);
517 517 fname = cname = entry = NULL;
518 518 pos += flen;
519 519 }
520 520
521 521 ret = parents;
522 522 Py_INCREF(ret);
523 523 quit:
524 524 Py_XDECREF(fname);
525 525 Py_XDECREF(cname);
526 526 Py_XDECREF(entry);
527 527 Py_XDECREF(parents);
528 528 return ret;
529 529 }
530 530
531 531 /*
532 532 * Build a set of non-normal and other parent entries from the dirstate dmap
533 533 */
534 534 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args) {
535 535 PyObject *dmap, *fname, *v;
536 536 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
537 537 Py_ssize_t pos;
538 538
539 539 if (!PyArg_ParseTuple(args, "O!:nonnormalentries",
540 540 &PyDict_Type, &dmap))
541 541 goto bail;
542 542
543 543 nonnset = PySet_New(NULL);
544 544 if (nonnset == NULL)
545 545 goto bail;
546 546
547 547 otherpset = PySet_New(NULL);
548 548 if (otherpset == NULL)
549 549 goto bail;
550 550
551 551 pos = 0;
552 552 while (PyDict_Next(dmap, &pos, &fname, &v)) {
553 553 dirstateTupleObject *t;
554 554 if (!dirstate_tuple_check(v)) {
555 555 PyErr_SetString(PyExc_TypeError,
556 556 "expected a dirstate tuple");
557 557 goto bail;
558 558 }
559 559 t = (dirstateTupleObject *)v;
560 560
561 561 if (t->state == 'n' && t->size == -2) {
562 562 if (PySet_Add(otherpset, fname) == -1) {
563 563 goto bail;
564 564 }
565 565 }
566 566
567 567 if (t->state == 'n' && t->mtime != -1)
568 568 continue;
569 569 if (PySet_Add(nonnset, fname) == -1)
570 570 goto bail;
571 571 }
572 572
573 573 result = Py_BuildValue("(OO)", nonnset, otherpset);
574 574 if (result == NULL)
575 575 goto bail;
576 576 Py_DECREF(nonnset);
577 577 Py_DECREF(otherpset);
578 578 return result;
579 579 bail:
580 580 Py_XDECREF(nonnset);
581 581 Py_XDECREF(otherpset);
582 582 Py_XDECREF(result);
583 583 return NULL;
584 584 }
585 585
586 586 /*
587 587 * Efficiently pack a dirstate object into its on-disk format.
588 588 */
589 589 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
590 590 {
591 591 PyObject *packobj = NULL;
592 592 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
593 593 Py_ssize_t nbytes, pos, l;
594 594 PyObject *k, *v = NULL, *pn;
595 595 char *p, *s;
596 596 int now;
597 597
598 598 if (!PyArg_ParseTuple(args, "O!O!Oi:pack_dirstate",
599 599 &PyDict_Type, &map, &PyDict_Type, &copymap,
600 600 &pl, &now))
601 601 return NULL;
602 602
603 603 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
604 604 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
605 605 return NULL;
606 606 }
607 607
608 608 /* Figure out how much we need to allocate. */
609 609 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
610 610 PyObject *c;
611 611 if (!PyBytes_Check(k)) {
612 612 PyErr_SetString(PyExc_TypeError, "expected string key");
613 613 goto bail;
614 614 }
615 615 nbytes += PyBytes_GET_SIZE(k) + 17;
616 616 c = PyDict_GetItem(copymap, k);
617 617 if (c) {
618 618 if (!PyBytes_Check(c)) {
619 619 PyErr_SetString(PyExc_TypeError,
620 620 "expected string key");
621 621 goto bail;
622 622 }
623 623 nbytes += PyBytes_GET_SIZE(c) + 1;
624 624 }
625 625 }
626 626
627 627 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
628 628 if (packobj == NULL)
629 629 goto bail;
630 630
631 631 p = PyBytes_AS_STRING(packobj);
632 632
633 633 pn = PySequence_ITEM(pl, 0);
634 634 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
635 635 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
636 636 goto bail;
637 637 }
638 638 memcpy(p, s, l);
639 639 p += 20;
640 640 pn = PySequence_ITEM(pl, 1);
641 641 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
642 642 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
643 643 goto bail;
644 644 }
645 645 memcpy(p, s, l);
646 646 p += 20;
647 647
648 648 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
649 649 dirstateTupleObject *tuple;
650 650 char state;
651 651 int mode, size, mtime;
652 652 Py_ssize_t len, l;
653 653 PyObject *o;
654 654 char *t;
655 655
656 656 if (!dirstate_tuple_check(v)) {
657 657 PyErr_SetString(PyExc_TypeError,
658 658 "expected a dirstate tuple");
659 659 goto bail;
660 660 }
661 661 tuple = (dirstateTupleObject *)v;
662 662
663 663 state = tuple->state;
664 664 mode = tuple->mode;
665 665 size = tuple->size;
666 666 mtime = tuple->mtime;
667 667 if (state == 'n' && mtime == now) {
668 668 /* See pure/parsers.py:pack_dirstate for why we do
669 669 * this. */
670 670 mtime = -1;
671 671 mtime_unset = (PyObject *)make_dirstate_tuple(
672 672 state, mode, size, mtime);
673 673 if (!mtime_unset)
674 674 goto bail;
675 675 if (PyDict_SetItem(map, k, mtime_unset) == -1)
676 676 goto bail;
677 677 Py_DECREF(mtime_unset);
678 678 mtime_unset = NULL;
679 679 }
680 680 *p++ = state;
681 681 putbe32((uint32_t)mode, p);
682 682 putbe32((uint32_t)size, p + 4);
683 683 putbe32((uint32_t)mtime, p + 8);
684 684 t = p + 12;
685 685 p += 16;
686 686 len = PyBytes_GET_SIZE(k);
687 687 memcpy(p, PyBytes_AS_STRING(k), len);
688 688 p += len;
689 689 o = PyDict_GetItem(copymap, k);
690 690 if (o) {
691 691 *p++ = '\0';
692 692 l = PyBytes_GET_SIZE(o);
693 693 memcpy(p, PyBytes_AS_STRING(o), l);
694 694 p += l;
695 695 len += l + 1;
696 696 }
697 697 putbe32((uint32_t)len, t);
698 698 }
699 699
700 700 pos = p - PyBytes_AS_STRING(packobj);
701 701 if (pos != nbytes) {
702 702 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
703 703 (long)pos, (long)nbytes);
704 704 goto bail;
705 705 }
706 706
707 707 return packobj;
708 708 bail:
709 709 Py_XDECREF(mtime_unset);
710 710 Py_XDECREF(packobj);
711 711 Py_XDECREF(v);
712 712 return NULL;
713 713 }
714 714
715 715 #define BUMPED_FIX 1
716 716 #define USING_SHA_256 2
717 717 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
718 718
719 719 static PyObject *readshas(
720 720 const char *source, unsigned char num, Py_ssize_t hashwidth)
721 721 {
722 722 int i;
723 723 PyObject *list = PyTuple_New(num);
724 724 if (list == NULL) {
725 725 return NULL;
726 726 }
727 727 for (i = 0; i < num; i++) {
728 728 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
729 729 if (hash == NULL) {
730 730 Py_DECREF(list);
731 731 return NULL;
732 732 }
733 733 PyTuple_SET_ITEM(list, i, hash);
734 734 source += hashwidth;
735 735 }
736 736 return list;
737 737 }
738 738
739 739 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
740 740 uint32_t *msize)
741 741 {
742 742 const char *data = databegin;
743 743 const char *meta;
744 744
745 745 double mtime;
746 746 int16_t tz;
747 747 uint16_t flags;
748 748 unsigned char nsuccs, nparents, nmetadata;
749 749 Py_ssize_t hashwidth = 20;
750 750
751 751 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
752 752 PyObject *metadata = NULL, *ret = NULL;
753 753 int i;
754 754
755 755 if (data + FM1_HEADER_SIZE > dataend) {
756 756 goto overflow;
757 757 }
758 758
759 759 *msize = getbe32(data);
760 760 data += 4;
761 761 mtime = getbefloat64(data);
762 762 data += 8;
763 763 tz = getbeint16(data);
764 764 data += 2;
765 765 flags = getbeuint16(data);
766 766 data += 2;
767 767
768 768 if (flags & USING_SHA_256) {
769 769 hashwidth = 32;
770 770 }
771 771
772 772 nsuccs = (unsigned char)(*data++);
773 773 nparents = (unsigned char)(*data++);
774 774 nmetadata = (unsigned char)(*data++);
775 775
776 776 if (databegin + *msize > dataend) {
777 777 goto overflow;
778 778 }
779 779 dataend = databegin + *msize; /* narrow down to marker size */
780 780
781 781 if (data + hashwidth > dataend) {
782 782 goto overflow;
783 783 }
784 784 prec = PyBytes_FromStringAndSize(data, hashwidth);
785 785 data += hashwidth;
786 786 if (prec == NULL) {
787 787 goto bail;
788 788 }
789 789
790 790 if (data + nsuccs * hashwidth > dataend) {
791 791 goto overflow;
792 792 }
793 793 succs = readshas(data, nsuccs, hashwidth);
794 794 if (succs == NULL) {
795 795 goto bail;
796 796 }
797 797 data += nsuccs * hashwidth;
798 798
799 799 if (nparents == 1 || nparents == 2) {
800 800 if (data + nparents * hashwidth > dataend) {
801 801 goto overflow;
802 802 }
803 803 parents = readshas(data, nparents, hashwidth);
804 804 if (parents == NULL) {
805 805 goto bail;
806 806 }
807 807 data += nparents * hashwidth;
808 808 } else {
809 809 parents = Py_None;
810 810 Py_INCREF(parents);
811 811 }
812 812
813 813 if (data + 2 * nmetadata > dataend) {
814 814 goto overflow;
815 815 }
816 816 meta = data + (2 * nmetadata);
817 817 metadata = PyTuple_New(nmetadata);
818 818 if (metadata == NULL) {
819 819 goto bail;
820 820 }
821 821 for (i = 0; i < nmetadata; i++) {
822 822 PyObject *tmp, *left = NULL, *right = NULL;
823 823 Py_ssize_t leftsize = (unsigned char)(*data++);
824 824 Py_ssize_t rightsize = (unsigned char)(*data++);
825 825 if (meta + leftsize + rightsize > dataend) {
826 826 goto overflow;
827 827 }
828 828 left = PyBytes_FromStringAndSize(meta, leftsize);
829 829 meta += leftsize;
830 830 right = PyBytes_FromStringAndSize(meta, rightsize);
831 831 meta += rightsize;
832 832 tmp = PyTuple_New(2);
833 833 if (!left || !right || !tmp) {
834 834 Py_XDECREF(left);
835 835 Py_XDECREF(right);
836 836 Py_XDECREF(tmp);
837 837 goto bail;
838 838 }
839 839 PyTuple_SET_ITEM(tmp, 0, left);
840 840 PyTuple_SET_ITEM(tmp, 1, right);
841 841 PyTuple_SET_ITEM(metadata, i, tmp);
842 842 }
843 843 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags,
844 844 metadata, mtime, (int)tz * 60, parents);
845 845 goto bail; /* return successfully */
846 846
847 847 overflow:
848 848 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
849 849 bail:
850 850 Py_XDECREF(prec);
851 851 Py_XDECREF(succs);
852 852 Py_XDECREF(metadata);
853 853 Py_XDECREF(parents);
854 854 return ret;
855 855 }
856 856
857 857
858 858 static PyObject *fm1readmarkers(PyObject *self, PyObject *args) {
859 859 const char *data, *dataend;
860 860 int datalen;
861 861 Py_ssize_t offset, stop;
862 862 PyObject *markers = NULL;
863 863
864 864 if (!PyArg_ParseTuple(args, "s#nn", &data, &datalen, &offset, &stop)) {
865 865 return NULL;
866 866 }
867 867 dataend = data + datalen;
868 868 data += offset;
869 869 markers = PyList_New(0);
870 870 if (!markers) {
871 871 return NULL;
872 872 }
873 873 while (offset < stop) {
874 874 uint32_t msize;
875 875 int error;
876 876 PyObject *record = fm1readmarker(data, dataend, &msize);
877 877 if (!record) {
878 878 goto bail;
879 879 }
880 880 error = PyList_Append(markers, record);
881 881 Py_DECREF(record);
882 882 if (error) {
883 883 goto bail;
884 884 }
885 885 data += msize;
886 886 offset += msize;
887 887 }
888 888 return markers;
889 889 bail:
890 890 Py_DECREF(markers);
891 891 return NULL;
892 892 }
893 893
894 894 static char parsers_doc[] = "Efficient content parsing.";
895 895
896 896 PyObject *encodedir(PyObject *self, PyObject *args);
897 897 PyObject *pathencode(PyObject *self, PyObject *args);
898 898 PyObject *lowerencode(PyObject *self, PyObject *args);
899 899 PyObject *parse_index2(PyObject *self, PyObject *args);
900 900
901 901 static PyMethodDef methods[] = {
902 902 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
903 903 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
904 904 "create a set containing non-normal and other parent entries of given "
905 905 "dirstate\n"},
906 906 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
907 907 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
908 908 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
909 909 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
910 910 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
911 911 {"dict_new_presized", dict_new_presized, METH_VARARGS,
912 912 "construct a dict with an expected size\n"},
913 913 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
914 914 "make file foldmap\n"},
915 915 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
916 916 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
917 917 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
918 918 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
919 919 "parse v1 obsolete markers\n"},
920 920 {NULL, NULL}
921 921 };
922 922
923 923 void dirs_module_init(PyObject *mod);
924 924 void manifest_module_init(PyObject *mod);
925 925 void revlog_module_init(PyObject *mod);
926 926
927 927 static const int version = 1;
928 928
929 929 static void module_init(PyObject *mod)
930 930 {
931 931 PyModule_AddIntConstant(mod, "version", version);
932 932
933 933 /* This module constant has two purposes. First, it lets us unit test
934 934 * the ImportError raised without hard-coding any error text. This
935 935 * means we can change the text in the future without breaking tests,
936 936 * even across changesets without a recompile. Second, its presence
937 937 * can be used to determine whether the version-checking logic is
938 938 * present, which also helps in testing across changesets without a
939 939 * recompile. Note that this means the pure-Python version of parsers
940 940 * should not have this module constant. */
941 941 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
942 942
943 943 dirs_module_init(mod);
944 944 manifest_module_init(mod);
945 945 revlog_module_init(mod);
946 946
947 947 if (PyType_Ready(&dirstateTupleType) < 0)
948 948 return;
949 949 Py_INCREF(&dirstateTupleType);
950 950 PyModule_AddObject(mod, "dirstatetuple",
951 951 (PyObject *)&dirstateTupleType);
952 952 }
953 953
954 954 static int check_python_version(void)
955 955 {
956 956 PyObject *sys = PyImport_ImportModule("sys"), *ver;
957 957 long hexversion;
958 958 if (!sys)
959 959 return -1;
960 960 ver = PyObject_GetAttrString(sys, "hexversion");
961 961 Py_DECREF(sys);
962 962 if (!ver)
963 963 return -1;
964 964 hexversion = PyInt_AsLong(ver);
965 965 Py_DECREF(ver);
966 966 /* sys.hexversion is a 32-bit number by default, so the -1 case
967 967 * should only occur in unusual circumstances (e.g. if sys.hexversion
968 968 * is manually set to an invalid value). */
969 969 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
970 970 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
971 971 "modules were compiled with Python " PY_VERSION ", but "
972 972 "Mercurial is currently using Python with sys.hexversion=%ld: "
973 973 "Python %s\n at: %s", versionerrortext, hexversion,
974 974 Py_GetVersion(), Py_GetProgramFullPath());
975 975 return -1;
976 976 }
977 977 return 0;
978 978 }
979 979
980 980 #ifdef IS_PY3K
981 981 static struct PyModuleDef parsers_module = {
982 982 PyModuleDef_HEAD_INIT,
983 983 "parsers",
984 984 parsers_doc,
985 985 -1,
986 986 methods
987 987 };
988 988
989 989 PyMODINIT_FUNC PyInit_parsers(void)
990 990 {
991 991 PyObject *mod;
992 992
993 993 if (check_python_version() == -1)
994 994 return NULL;
995 995 mod = PyModule_Create(&parsers_module);
996 996 module_init(mod);
997 997 return mod;
998 998 }
999 999 #else
1000 1000 PyMODINIT_FUNC initparsers(void)
1001 1001 {
1002 1002 PyObject *mod;
1003 1003
1004 1004 if (check_python_version() == -1)
1005 1005 return;
1006 1006 mod = Py_InitModule3("parsers", methods, parsers_doc);
1007 1007 module_init(mod);
1008 1008 }
1009 1009 #endif
@@ -1,76 +1,76 b''
1 1 /*
2 2 util.h - utility functions for interfacing with the various python APIs.
3 3
4 4 This software may be used and distributed according to the terms of
5 5 the GNU General Public License, incorporated herein by reference.
6 6 */
7 7
8 8 #ifndef _HG_UTIL_H_
9 9 #define _HG_UTIL_H_
10 10
11 11 #include "compat.h"
12 12
13 13 #if PY_MAJOR_VERSION >= 3
14 14 #define IS_PY3K
15 15 #endif
16 16
17 17 typedef struct {
18 18 PyObject_HEAD
19 19 char state;
20 20 int mode;
21 21 int size;
22 22 int mtime;
23 23 } dirstateTupleObject;
24 24
25 25 extern PyTypeObject dirstateTupleType;
26 26 #define dirstate_tuple_check(op) (Py_TYPE(op) == &dirstateTupleType)
27 27
28 28 /* This should be kept in sync with normcasespecs in encoding.py. */
29 29 enum normcase_spec {
30 30 NORMCASE_LOWER = -1,
31 31 NORMCASE_UPPER = 1,
32 32 NORMCASE_OTHER = 0
33 33 };
34 34
35 35 #define MIN(a, b) (((a)<(b))?(a):(b))
36 36 /* VC9 doesn't include bool and lacks stdbool.h based on my searching */
37 37 #if defined(_MSC_VER) || __STDC_VERSION__ < 199901L
38 38 #define true 1
39 39 #define false 0
40 40 typedef unsigned char bool;
41 41 #else
42 42 #include <stdbool.h>
43 43 #endif
44 44
45 static int8_t hextable[256] = {
45 static const int8_t hextable[256] = {
46 46 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
47 47 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48 48 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
49 49 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
50 50 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
51 51 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
52 52 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
53 53 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
54 54 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
55 55 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
56 56 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
57 57 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
58 58 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
59 59 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
60 60 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
61 61 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
62 62 };
63 63
64 64 static inline int hexdigit(const char *p, Py_ssize_t off)
65 65 {
66 66 int8_t val = hextable[(unsigned char)p[off]];
67 67
68 68 if (val >= 0) {
69 69 return val;
70 70 }
71 71
72 72 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
73 73 return 0;
74 74 }
75 75
76 76 #endif /* _HG_UTIL_H_ */
General Comments 0
You need to be logged in to leave comments. Login now