##// END OF EJS Templates
dirstate: fix parse_dirstate() to error out if NULL entry created...
Yuya Nishihara -
r48839:13efd8fd default
parent child Browse files
Show More
@@ -1,1320 +1,1322 b''
1 1 /*
2 2 parsers.c - efficient content parsing
3 3
4 4 Copyright 2008 Olivia Mackall <olivia@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 #define PY_SSIZE_T_CLEAN
11 11 #include <Python.h>
12 12 #include <ctype.h>
13 13 #include <stddef.h>
14 14 #include <string.h>
15 15
16 16 #include "bitmanipulation.h"
17 17 #include "charencode.h"
18 18 #include "util.h"
19 19
20 20 #ifdef IS_PY3K
21 21 /* The mapping of Python types is meant to be temporary to get Python
22 22 * 3 to compile. We should remove this once Python 3 support is fully
23 23 * supported and proper types are used in the extensions themselves. */
24 24 #define PyInt_Check PyLong_Check
25 25 #define PyInt_FromLong PyLong_FromLong
26 26 #define PyInt_FromSsize_t PyLong_FromSsize_t
27 27 #define PyInt_AsLong PyLong_AsLong
28 28 #endif
29 29
30 30 static const char *const versionerrortext = "Python minor version mismatch";
31 31
32 32 static const int dirstate_v1_from_p2 = -2;
33 33 static const int dirstate_v1_nonnormal = -1;
34 34 static const int ambiguous_time = -1;
35 35
36 36 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
37 37 {
38 38 Py_ssize_t expected_size;
39 39
40 40 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size)) {
41 41 return NULL;
42 42 }
43 43
44 44 return _dict_new_presized(expected_size);
45 45 }
46 46
47 47 static PyObject *dirstate_item_new(PyTypeObject *subtype, PyObject *args,
48 48 PyObject *kwds)
49 49 {
50 50 /* We do all the initialization here and not a tp_init function because
51 51 * dirstate_item is immutable. */
52 52 dirstateItemObject *t;
53 53 int wc_tracked;
54 54 int p1_tracked;
55 55 int p2_tracked;
56 56 int merged;
57 57 int clean_p1;
58 58 int clean_p2;
59 59 int possibly_dirty;
60 60 PyObject *parentfiledata;
61 61 static char *keywords_name[] = {
62 62 "wc_tracked", "p1_tracked", "p2_tracked",
63 63 "merged", "clean_p1", "clean_p2",
64 64 "possibly_dirty", "parentfiledata", NULL,
65 65 };
66 66 wc_tracked = 0;
67 67 p1_tracked = 0;
68 68 p2_tracked = 0;
69 69 merged = 0;
70 70 clean_p1 = 0;
71 71 clean_p2 = 0;
72 72 possibly_dirty = 0;
73 73 parentfiledata = Py_None;
74 74 if (!PyArg_ParseTupleAndKeywords(args, kwds, "iiiiiiiO", keywords_name,
75 75 &wc_tracked, &p1_tracked, &p2_tracked,
76 76 &merged, &clean_p1, &clean_p2,
77 77 &possibly_dirty, &parentfiledata
78 78
79 79 )) {
80 80 return NULL;
81 81 }
82 82 if (merged && (clean_p1 || clean_p2)) {
83 83 PyErr_SetString(PyExc_RuntimeError,
84 84 "`merged` argument incompatible with "
85 85 "`clean_p1`/`clean_p2`");
86 86 return NULL;
87 87 }
88 88 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
89 89 if (!t) {
90 90 return NULL;
91 91 }
92 92
93 93 t->flags = 0;
94 94 if (wc_tracked) {
95 95 t->flags |= dirstate_flag_wc_tracked;
96 96 }
97 97 if (p1_tracked) {
98 98 t->flags |= dirstate_flag_p1_tracked;
99 99 }
100 100 if (p2_tracked) {
101 101 t->flags |= dirstate_flag_p2_tracked;
102 102 }
103 103 if (possibly_dirty) {
104 104 t->flags |= dirstate_flag_possibly_dirty;
105 105 }
106 106 if (merged) {
107 107 t->flags |= dirstate_flag_merged;
108 108 }
109 109 if (clean_p1) {
110 110 t->flags |= dirstate_flag_clean_p1;
111 111 }
112 112 if (clean_p2) {
113 113 t->flags |= dirstate_flag_clean_p2;
114 114 }
115 115 t->mode = 0;
116 116 t->size = dirstate_v1_nonnormal;
117 117 t->mtime = ambiguous_time;
118 118 if (parentfiledata != Py_None) {
119 119 if (!PyTuple_CheckExact(parentfiledata)) {
120 120 PyErr_SetString(
121 121 PyExc_TypeError,
122 122 "parentfiledata should be a Tuple or None");
123 123 return NULL;
124 124 }
125 125 t->mode =
126 126 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 0));
127 127 t->size =
128 128 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 1));
129 129 t->mtime =
130 130 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 2));
131 131 }
132 132 return (PyObject *)t;
133 133 }
134 134
135 135 static void dirstate_item_dealloc(PyObject *o)
136 136 {
137 137 PyObject_Del(o);
138 138 }
139 139
140 140 static inline bool dirstate_item_c_tracked(dirstateItemObject *self)
141 141 {
142 142 return (self->flags & dirstate_flag_wc_tracked);
143 143 }
144 144
145 145 static inline bool dirstate_item_c_added(dirstateItemObject *self)
146 146 {
147 147 unsigned char mask =
148 148 (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
149 149 dirstate_flag_p2_tracked);
150 150 unsigned char target = dirstate_flag_wc_tracked;
151 151 return (self->flags & mask) == target;
152 152 }
153 153
154 154 static inline bool dirstate_item_c_removed(dirstateItemObject *self)
155 155 {
156 156 if (self->flags & dirstate_flag_wc_tracked) {
157 157 return false;
158 158 }
159 159 return (self->flags &
160 160 (dirstate_flag_p1_tracked | dirstate_flag_p2_tracked));
161 161 }
162 162
163 163 static inline bool dirstate_item_c_merged(dirstateItemObject *self)
164 164 {
165 165 return ((self->flags & dirstate_flag_wc_tracked) &&
166 166 (self->flags & dirstate_flag_merged));
167 167 }
168 168
169 169 static inline bool dirstate_item_c_merged_removed(dirstateItemObject *self)
170 170 {
171 171 if (!dirstate_item_c_removed(self)) {
172 172 return false;
173 173 }
174 174 return (self->flags & dirstate_flag_merged);
175 175 }
176 176
177 177 static inline bool dirstate_item_c_from_p2(dirstateItemObject *self)
178 178 {
179 179 if (!dirstate_item_c_tracked(self)) {
180 180 return false;
181 181 }
182 182 return (self->flags & dirstate_flag_clean_p2);
183 183 }
184 184
185 185 static inline bool dirstate_item_c_from_p2_removed(dirstateItemObject *self)
186 186 {
187 187 if (!dirstate_item_c_removed(self)) {
188 188 return false;
189 189 }
190 190 return (self->flags & dirstate_flag_clean_p2);
191 191 }
192 192
193 193 static inline char dirstate_item_c_v1_state(dirstateItemObject *self)
194 194 {
195 195 if (dirstate_item_c_removed(self)) {
196 196 return 'r';
197 197 } else if (dirstate_item_c_merged(self)) {
198 198 return 'm';
199 199 } else if (dirstate_item_c_added(self)) {
200 200 return 'a';
201 201 } else {
202 202 return 'n';
203 203 }
204 204 }
205 205
206 206 static inline int dirstate_item_c_v1_mode(dirstateItemObject *self)
207 207 {
208 208 return self->mode;
209 209 }
210 210
211 211 static inline int dirstate_item_c_v1_size(dirstateItemObject *self)
212 212 {
213 213 if (dirstate_item_c_merged_removed(self)) {
214 214 return dirstate_v1_nonnormal;
215 215 } else if (dirstate_item_c_from_p2_removed(self)) {
216 216 return dirstate_v1_from_p2;
217 217 } else if (dirstate_item_c_removed(self)) {
218 218 return 0;
219 219 } else if (dirstate_item_c_merged(self)) {
220 220 return dirstate_v1_from_p2;
221 221 } else if (dirstate_item_c_added(self)) {
222 222 return dirstate_v1_nonnormal;
223 223 } else if (dirstate_item_c_from_p2(self)) {
224 224 return dirstate_v1_from_p2;
225 225 } else if (self->flags & dirstate_flag_possibly_dirty) {
226 226 return self->size; /* NON NORMAL ? */
227 227 } else {
228 228 return self->size;
229 229 }
230 230 }
231 231
232 232 static inline int dirstate_item_c_v1_mtime(dirstateItemObject *self)
233 233 {
234 234 if (dirstate_item_c_removed(self)) {
235 235 return 0;
236 236 } else if (self->flags & dirstate_flag_possibly_dirty) {
237 237 return ambiguous_time;
238 238 } else if (dirstate_item_c_merged(self)) {
239 239 return ambiguous_time;
240 240 } else if (dirstate_item_c_added(self)) {
241 241 return ambiguous_time;
242 242 } else if (dirstate_item_c_from_p2(self)) {
243 243 return ambiguous_time;
244 244 } else {
245 245 return self->mtime;
246 246 }
247 247 }
248 248
249 249 static PyObject *dirstate_item_v1_state(dirstateItemObject *self)
250 250 {
251 251 char state = dirstate_item_c_v1_state(self);
252 252 return PyBytes_FromStringAndSize(&state, 1);
253 253 };
254 254
255 255 static PyObject *dirstate_item_v1_mode(dirstateItemObject *self)
256 256 {
257 257 return PyInt_FromLong(dirstate_item_c_v1_mode(self));
258 258 };
259 259
260 260 static PyObject *dirstate_item_v1_size(dirstateItemObject *self)
261 261 {
262 262 return PyInt_FromLong(dirstate_item_c_v1_size(self));
263 263 };
264 264
265 265 static PyObject *dirstate_item_v1_mtime(dirstateItemObject *self)
266 266 {
267 267 return PyInt_FromLong(dirstate_item_c_v1_mtime(self));
268 268 };
269 269
270 270 static PyObject *dirstate_item_need_delay(dirstateItemObject *self,
271 271 PyObject *value)
272 272 {
273 273 long now;
274 274 if (!pylong_to_long(value, &now)) {
275 275 return NULL;
276 276 }
277 277 if (dirstate_item_c_v1_state(self) == 'n' &&
278 278 dirstate_item_c_v1_mtime(self) == now) {
279 279 Py_RETURN_TRUE;
280 280 } else {
281 281 Py_RETURN_FALSE;
282 282 }
283 283 };
284 284
285 285 /* This will never change since it's bound to V1
286 286 */
287 287 static inline dirstateItemObject *
288 288 dirstate_item_from_v1_data(char state, int mode, int size, int mtime)
289 289 {
290 290 dirstateItemObject *t =
291 291 PyObject_New(dirstateItemObject, &dirstateItemType);
292 292 if (!t) {
293 293 return NULL;
294 294 }
295 295
296 296 if (state == 'm') {
297 297 t->flags =
298 298 (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
299 299 dirstate_flag_p2_tracked | dirstate_flag_merged);
300 300 t->mode = 0;
301 301 t->size = dirstate_v1_from_p2;
302 302 t->mtime = ambiguous_time;
303 303 } else if (state == 'a') {
304 304 t->flags = dirstate_flag_wc_tracked;
305 305 t->mode = 0;
306 306 t->size = dirstate_v1_nonnormal;
307 307 t->mtime = ambiguous_time;
308 308 } else if (state == 'r') {
309 309 t->mode = 0;
310 310 t->size = 0;
311 311 t->mtime = 0;
312 312 if (size == dirstate_v1_nonnormal) {
313 313 t->flags =
314 314 (dirstate_flag_p1_tracked |
315 315 dirstate_flag_p2_tracked | dirstate_flag_merged);
316 316 } else if (size == dirstate_v1_from_p2) {
317 317 t->flags =
318 318 (dirstate_flag_p2_tracked | dirstate_flag_clean_p2);
319 319 } else {
320 320 t->flags = dirstate_flag_p1_tracked;
321 321 }
322 322 } else if (state == 'n') {
323 323 if (size == dirstate_v1_from_p2) {
324 324 t->flags =
325 325 (dirstate_flag_wc_tracked |
326 326 dirstate_flag_p2_tracked | dirstate_flag_clean_p2);
327 327 t->mode = 0;
328 328 t->size = dirstate_v1_from_p2;
329 329 t->mtime = ambiguous_time;
330 330 } else if (size == dirstate_v1_nonnormal) {
331 331 t->flags = (dirstate_flag_wc_tracked |
332 332 dirstate_flag_p1_tracked |
333 333 dirstate_flag_possibly_dirty);
334 334 t->mode = 0;
335 335 t->size = dirstate_v1_nonnormal;
336 336 t->mtime = ambiguous_time;
337 337 } else if (mtime == ambiguous_time) {
338 338 t->flags = (dirstate_flag_wc_tracked |
339 339 dirstate_flag_p1_tracked |
340 340 dirstate_flag_possibly_dirty);
341 341 t->mode = mode;
342 342 t->size = size;
343 343 t->mtime = 0;
344 344 } else {
345 345 t->flags = (dirstate_flag_wc_tracked |
346 346 dirstate_flag_p1_tracked);
347 347 t->mode = mode;
348 348 t->size = size;
349 349 t->mtime = mtime;
350 350 }
351 351 } else {
352 352 PyErr_Format(PyExc_RuntimeError,
353 353 "unknown state: `%c` (%d, %d, %d)", state, mode,
354 354 size, mtime, NULL);
355 355 return NULL;
356 356 }
357 357
358 358 return t;
359 359 }
360 360
361 361 /* This will never change since it's bound to V1, unlike `dirstate_item_new` */
362 362 static PyObject *dirstate_item_from_v1_meth(PyTypeObject *subtype,
363 363 PyObject *args)
364 364 {
365 365 /* We do all the initialization here and not a tp_init function because
366 366 * dirstate_item is immutable. */
367 367 char state;
368 368 int size, mode, mtime;
369 369 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
370 370 return NULL;
371 371 }
372 372 return (PyObject *)dirstate_item_from_v1_data(state, mode, size, mtime);
373 373 };
374 374
375 375 /* constructor to help legacy API to build a new "added" item
376 376
377 377 Should eventually be removed */
378 378 static PyObject *dirstate_item_new_added(PyTypeObject *subtype)
379 379 {
380 380 dirstateItemObject *t;
381 381 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
382 382 if (!t) {
383 383 return NULL;
384 384 }
385 385 t->flags = dirstate_flag_wc_tracked;
386 386 t->mode = 0;
387 387 t->size = dirstate_v1_nonnormal;
388 388 t->mtime = ambiguous_time;
389 389 return (PyObject *)t;
390 390 };
391 391
392 392 /* constructor to help legacy API to build a new "merged" item
393 393
394 394 Should eventually be removed */
395 395 static PyObject *dirstate_item_new_merged(PyTypeObject *subtype)
396 396 {
397 397 dirstateItemObject *t;
398 398 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
399 399 if (!t) {
400 400 return NULL;
401 401 }
402 402 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
403 403 dirstate_flag_p2_tracked | dirstate_flag_merged);
404 404 t->mode = 0;
405 405 t->size = dirstate_v1_from_p2;
406 406 t->mtime = ambiguous_time;
407 407 return (PyObject *)t;
408 408 };
409 409
410 410 /* constructor to help legacy API to build a new "from_p2" item
411 411
412 412 Should eventually be removed */
413 413 static PyObject *dirstate_item_new_from_p2(PyTypeObject *subtype)
414 414 {
415 415 /* We do all the initialization here and not a tp_init function because
416 416 * dirstate_item is immutable. */
417 417 dirstateItemObject *t;
418 418 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
419 419 if (!t) {
420 420 return NULL;
421 421 }
422 422 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p2_tracked |
423 423 dirstate_flag_clean_p2);
424 424 t->mode = 0;
425 425 t->size = dirstate_v1_from_p2;
426 426 t->mtime = ambiguous_time;
427 427 return (PyObject *)t;
428 428 };
429 429
430 430 /* constructor to help legacy API to build a new "possibly" item
431 431
432 432 Should eventually be removed */
433 433 static PyObject *dirstate_item_new_possibly_dirty(PyTypeObject *subtype)
434 434 {
435 435 /* We do all the initialization here and not a tp_init function because
436 436 * dirstate_item is immutable. */
437 437 dirstateItemObject *t;
438 438 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
439 439 if (!t) {
440 440 return NULL;
441 441 }
442 442 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
443 443 dirstate_flag_possibly_dirty);
444 444 t->mode = 0;
445 445 t->size = dirstate_v1_nonnormal;
446 446 t->mtime = ambiguous_time;
447 447 return (PyObject *)t;
448 448 };
449 449
450 450 /* constructor to help legacy API to build a new "normal" item
451 451
452 452 Should eventually be removed */
453 453 static PyObject *dirstate_item_new_normal(PyTypeObject *subtype, PyObject *args)
454 454 {
455 455 /* We do all the initialization here and not a tp_init function because
456 456 * dirstate_item is immutable. */
457 457 dirstateItemObject *t;
458 458 int size, mode, mtime;
459 459 if (!PyArg_ParseTuple(args, "iii", &mode, &size, &mtime)) {
460 460 return NULL;
461 461 }
462 462
463 463 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
464 464 if (!t) {
465 465 return NULL;
466 466 }
467 467 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked);
468 468 t->mode = mode;
469 469 t->size = size;
470 470 t->mtime = mtime;
471 471 return (PyObject *)t;
472 472 };
473 473
474 474 /* This means the next status call will have to actually check its content
475 475 to make sure it is correct. */
476 476 static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
477 477 {
478 478 self->flags |= dirstate_flag_possibly_dirty;
479 479 Py_RETURN_NONE;
480 480 }
481 481
482 482 /* See docstring of the python implementation for details */
483 483 static PyObject *dirstate_item_set_clean(dirstateItemObject *self,
484 484 PyObject *args)
485 485 {
486 486 int size, mode, mtime;
487 487 if (!PyArg_ParseTuple(args, "iii", &mode, &size, &mtime)) {
488 488 return NULL;
489 489 }
490 490 self->flags = dirstate_flag_wc_tracked | dirstate_flag_p1_tracked;
491 491 self->mode = mode;
492 492 self->size = size;
493 493 self->mtime = mtime;
494 494 Py_RETURN_NONE;
495 495 }
496 496
497 497 static PyObject *dirstate_item_set_tracked(dirstateItemObject *self)
498 498 {
499 499 self->flags |= dirstate_flag_wc_tracked;
500 500 self->flags |= dirstate_flag_possibly_dirty;
501 501 /* size = None on the python size turn into size = NON_NORMAL when
502 502 * accessed. So the next line is currently required, but a some future
503 503 * clean up would be welcome. */
504 504 self->size = dirstate_v1_nonnormal;
505 505 Py_RETURN_NONE;
506 506 }
507 507
508 508 static PyObject *dirstate_item_set_untracked(dirstateItemObject *self)
509 509 {
510 510 self->flags &= ~dirstate_flag_wc_tracked;
511 511 self->mode = 0;
512 512 self->mtime = 0;
513 513 self->size = 0;
514 514 Py_RETURN_NONE;
515 515 }
516 516
517 517 static PyMethodDef dirstate_item_methods[] = {
518 518 {"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS,
519 519 "return a \"state\" suitable for v1 serialization"},
520 520 {"v1_mode", (PyCFunction)dirstate_item_v1_mode, METH_NOARGS,
521 521 "return a \"mode\" suitable for v1 serialization"},
522 522 {"v1_size", (PyCFunction)dirstate_item_v1_size, METH_NOARGS,
523 523 "return a \"size\" suitable for v1 serialization"},
524 524 {"v1_mtime", (PyCFunction)dirstate_item_v1_mtime, METH_NOARGS,
525 525 "return a \"mtime\" suitable for v1 serialization"},
526 526 {"need_delay", (PyCFunction)dirstate_item_need_delay, METH_O,
527 527 "True if the stored mtime would be ambiguous with the current time"},
528 528 {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth,
529 529 METH_VARARGS | METH_CLASS, "build a new DirstateItem object from V1 data"},
530 530 {"new_added", (PyCFunction)dirstate_item_new_added,
531 531 METH_NOARGS | METH_CLASS,
532 532 "constructor to help legacy API to build a new \"added\" item"},
533 533 {"new_merged", (PyCFunction)dirstate_item_new_merged,
534 534 METH_NOARGS | METH_CLASS,
535 535 "constructor to help legacy API to build a new \"merged\" item"},
536 536 {"new_from_p2", (PyCFunction)dirstate_item_new_from_p2,
537 537 METH_NOARGS | METH_CLASS,
538 538 "constructor to help legacy API to build a new \"from_p2\" item"},
539 539 {"new_possibly_dirty", (PyCFunction)dirstate_item_new_possibly_dirty,
540 540 METH_NOARGS | METH_CLASS,
541 541 "constructor to help legacy API to build a new \"possibly_dirty\" item"},
542 542 {"new_normal", (PyCFunction)dirstate_item_new_normal,
543 543 METH_VARARGS | METH_CLASS,
544 544 "constructor to help legacy API to build a new \"normal\" item"},
545 545 {"set_possibly_dirty", (PyCFunction)dirstate_item_set_possibly_dirty,
546 546 METH_NOARGS, "mark a file as \"possibly dirty\""},
547 547 {"set_clean", (PyCFunction)dirstate_item_set_clean, METH_VARARGS,
548 548 "mark a file as \"clean\""},
549 549 {"set_tracked", (PyCFunction)dirstate_item_set_tracked, METH_NOARGS,
550 550 "mark a file as \"tracked\""},
551 551 {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS,
552 552 "mark a file as \"untracked\""},
553 553 {NULL} /* Sentinel */
554 554 };
555 555
556 556 static PyObject *dirstate_item_get_mode(dirstateItemObject *self)
557 557 {
558 558 return PyInt_FromLong(dirstate_item_c_v1_mode(self));
559 559 };
560 560
561 561 static PyObject *dirstate_item_get_size(dirstateItemObject *self)
562 562 {
563 563 return PyInt_FromLong(dirstate_item_c_v1_size(self));
564 564 };
565 565
566 566 static PyObject *dirstate_item_get_mtime(dirstateItemObject *self)
567 567 {
568 568 return PyInt_FromLong(dirstate_item_c_v1_mtime(self));
569 569 };
570 570
571 571 static PyObject *dirstate_item_get_state(dirstateItemObject *self)
572 572 {
573 573 char state = dirstate_item_c_v1_state(self);
574 574 return PyBytes_FromStringAndSize(&state, 1);
575 575 };
576 576
577 577 static PyObject *dirstate_item_get_tracked(dirstateItemObject *self)
578 578 {
579 579 if (dirstate_item_c_tracked(self)) {
580 580 Py_RETURN_TRUE;
581 581 } else {
582 582 Py_RETURN_FALSE;
583 583 }
584 584 };
585 585
586 586 static PyObject *dirstate_item_get_added(dirstateItemObject *self)
587 587 {
588 588 if (dirstate_item_c_added(self)) {
589 589 Py_RETURN_TRUE;
590 590 } else {
591 591 Py_RETURN_FALSE;
592 592 }
593 593 };
594 594
595 595 static PyObject *dirstate_item_get_merged(dirstateItemObject *self)
596 596 {
597 597 if (dirstate_item_c_merged(self)) {
598 598 Py_RETURN_TRUE;
599 599 } else {
600 600 Py_RETURN_FALSE;
601 601 }
602 602 };
603 603
604 604 static PyObject *dirstate_item_get_merged_removed(dirstateItemObject *self)
605 605 {
606 606 if (dirstate_item_c_merged_removed(self)) {
607 607 Py_RETURN_TRUE;
608 608 } else {
609 609 Py_RETURN_FALSE;
610 610 }
611 611 };
612 612
613 613 static PyObject *dirstate_item_get_from_p2(dirstateItemObject *self)
614 614 {
615 615 if (dirstate_item_c_from_p2(self)) {
616 616 Py_RETURN_TRUE;
617 617 } else {
618 618 Py_RETURN_FALSE;
619 619 }
620 620 };
621 621
622 622 static PyObject *dirstate_item_get_from_p2_removed(dirstateItemObject *self)
623 623 {
624 624 if (dirstate_item_c_from_p2_removed(self)) {
625 625 Py_RETURN_TRUE;
626 626 } else {
627 627 Py_RETURN_FALSE;
628 628 }
629 629 };
630 630
631 631 static PyObject *dirstate_item_get_removed(dirstateItemObject *self)
632 632 {
633 633 if (dirstate_item_c_removed(self)) {
634 634 Py_RETURN_TRUE;
635 635 } else {
636 636 Py_RETURN_FALSE;
637 637 }
638 638 };
639 639
640 640 static PyObject *dm_nonnormal(dirstateItemObject *self)
641 641 {
642 642 if ((dirstate_item_c_v1_state(self) != 'n') ||
643 643 (dirstate_item_c_v1_mtime(self) == ambiguous_time)) {
644 644 Py_RETURN_TRUE;
645 645 } else {
646 646 Py_RETURN_FALSE;
647 647 }
648 648 };
649 649 static PyObject *dm_otherparent(dirstateItemObject *self)
650 650 {
651 651 if (dirstate_item_c_v1_mtime(self) == dirstate_v1_from_p2) {
652 652 Py_RETURN_TRUE;
653 653 } else {
654 654 Py_RETURN_FALSE;
655 655 }
656 656 };
657 657
658 658 static PyGetSetDef dirstate_item_getset[] = {
659 659 {"mode", (getter)dirstate_item_get_mode, NULL, "mode", NULL},
660 660 {"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
661 661 {"mtime", (getter)dirstate_item_get_mtime, NULL, "mtime", NULL},
662 662 {"state", (getter)dirstate_item_get_state, NULL, "state", NULL},
663 663 {"tracked", (getter)dirstate_item_get_tracked, NULL, "tracked", NULL},
664 664 {"added", (getter)dirstate_item_get_added, NULL, "added", NULL},
665 665 {"merged_removed", (getter)dirstate_item_get_merged_removed, NULL,
666 666 "merged_removed", NULL},
667 667 {"merged", (getter)dirstate_item_get_merged, NULL, "merged", NULL},
668 668 {"from_p2_removed", (getter)dirstate_item_get_from_p2_removed, NULL,
669 669 "from_p2_removed", NULL},
670 670 {"from_p2", (getter)dirstate_item_get_from_p2, NULL, "from_p2", NULL},
671 671 {"removed", (getter)dirstate_item_get_removed, NULL, "removed", NULL},
672 672 {"dm_nonnormal", (getter)dm_nonnormal, NULL, "dm_nonnormal", NULL},
673 673 {"dm_otherparent", (getter)dm_otherparent, NULL, "dm_otherparent", NULL},
674 674 {NULL} /* Sentinel */
675 675 };
676 676
677 677 PyTypeObject dirstateItemType = {
678 678 PyVarObject_HEAD_INIT(NULL, 0) /* header */
679 679 "dirstate_tuple", /* tp_name */
680 680 sizeof(dirstateItemObject), /* tp_basicsize */
681 681 0, /* tp_itemsize */
682 682 (destructor)dirstate_item_dealloc, /* tp_dealloc */
683 683 0, /* tp_print */
684 684 0, /* tp_getattr */
685 685 0, /* tp_setattr */
686 686 0, /* tp_compare */
687 687 0, /* tp_repr */
688 688 0, /* tp_as_number */
689 689 0, /* tp_as_sequence */
690 690 0, /* tp_as_mapping */
691 691 0, /* tp_hash */
692 692 0, /* tp_call */
693 693 0, /* tp_str */
694 694 0, /* tp_getattro */
695 695 0, /* tp_setattro */
696 696 0, /* tp_as_buffer */
697 697 Py_TPFLAGS_DEFAULT, /* tp_flags */
698 698 "dirstate tuple", /* tp_doc */
699 699 0, /* tp_traverse */
700 700 0, /* tp_clear */
701 701 0, /* tp_richcompare */
702 702 0, /* tp_weaklistoffset */
703 703 0, /* tp_iter */
704 704 0, /* tp_iternext */
705 705 dirstate_item_methods, /* tp_methods */
706 706 0, /* tp_members */
707 707 dirstate_item_getset, /* tp_getset */
708 708 0, /* tp_base */
709 709 0, /* tp_dict */
710 710 0, /* tp_descr_get */
711 711 0, /* tp_descr_set */
712 712 0, /* tp_dictoffset */
713 713 0, /* tp_init */
714 714 0, /* tp_alloc */
715 715 dirstate_item_new, /* tp_new */
716 716 };
717 717
718 718 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
719 719 {
720 720 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
721 721 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
722 722 char state, *cur, *str, *cpos;
723 723 int mode, size, mtime;
724 724 unsigned int flen, pos = 40;
725 725 Py_ssize_t len = 40;
726 726 Py_ssize_t readlen;
727 727
728 728 if (!PyArg_ParseTuple(
729 729 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
730 730 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen)) {
731 731 goto quit;
732 732 }
733 733
734 734 len = readlen;
735 735
736 736 /* read parents */
737 737 if (len < 40) {
738 738 PyErr_SetString(PyExc_ValueError,
739 739 "too little data for parents");
740 740 goto quit;
741 741 }
742 742
743 743 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, (Py_ssize_t)20,
744 744 str + 20, (Py_ssize_t)20);
745 745 if (!parents) {
746 746 goto quit;
747 747 }
748 748
749 749 /* read filenames */
750 750 while (pos >= 40 && pos < len) {
751 751 if (pos + 17 > len) {
752 752 PyErr_SetString(PyExc_ValueError,
753 753 "overflow in dirstate");
754 754 goto quit;
755 755 }
756 756 cur = str + pos;
757 757 /* unpack header */
758 758 state = *cur;
759 759 mode = getbe32(cur + 1);
760 760 size = getbe32(cur + 5);
761 761 mtime = getbe32(cur + 9);
762 762 flen = getbe32(cur + 13);
763 763 pos += 17;
764 764 cur += 17;
765 765 if (flen > len - pos) {
766 766 PyErr_SetString(PyExc_ValueError,
767 767 "overflow in dirstate");
768 768 goto quit;
769 769 }
770 770
771 771 entry = (PyObject *)dirstate_item_from_v1_data(state, mode,
772 772 size, mtime);
773 if (!entry)
774 goto quit;
773 775 cpos = memchr(cur, 0, flen);
774 776 if (cpos) {
775 777 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
776 778 cname = PyBytes_FromStringAndSize(
777 779 cpos + 1, flen - (cpos - cur) - 1);
778 780 if (!fname || !cname ||
779 781 PyDict_SetItem(cmap, fname, cname) == -1 ||
780 782 PyDict_SetItem(dmap, fname, entry) == -1) {
781 783 goto quit;
782 784 }
783 785 Py_DECREF(cname);
784 786 } else {
785 787 fname = PyBytes_FromStringAndSize(cur, flen);
786 788 if (!fname ||
787 789 PyDict_SetItem(dmap, fname, entry) == -1) {
788 790 goto quit;
789 791 }
790 792 }
791 793 Py_DECREF(fname);
792 794 Py_DECREF(entry);
793 795 fname = cname = entry = NULL;
794 796 pos += flen;
795 797 }
796 798
797 799 ret = parents;
798 800 Py_INCREF(ret);
799 801 quit:
800 802 Py_XDECREF(fname);
801 803 Py_XDECREF(cname);
802 804 Py_XDECREF(entry);
803 805 Py_XDECREF(parents);
804 806 return ret;
805 807 }
806 808
807 809 /*
808 810 * Build a set of non-normal and other parent entries from the dirstate dmap
809 811 */
810 812 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
811 813 {
812 814 PyObject *dmap, *fname, *v;
813 815 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
814 816 Py_ssize_t pos;
815 817
816 818 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type,
817 819 &dmap)) {
818 820 goto bail;
819 821 }
820 822
821 823 nonnset = PySet_New(NULL);
822 824 if (nonnset == NULL) {
823 825 goto bail;
824 826 }
825 827
826 828 otherpset = PySet_New(NULL);
827 829 if (otherpset == NULL) {
828 830 goto bail;
829 831 }
830 832
831 833 pos = 0;
832 834 while (PyDict_Next(dmap, &pos, &fname, &v)) {
833 835 dirstateItemObject *t;
834 836 if (!dirstate_tuple_check(v)) {
835 837 PyErr_SetString(PyExc_TypeError,
836 838 "expected a dirstate tuple");
837 839 goto bail;
838 840 }
839 841 t = (dirstateItemObject *)v;
840 842
841 843 if (dirstate_item_c_from_p2(t)) {
842 844 if (PySet_Add(otherpset, fname) == -1) {
843 845 goto bail;
844 846 }
845 847 }
846 848 if (!(t->flags & dirstate_flag_wc_tracked) ||
847 849 !(t->flags &
848 850 (dirstate_flag_p1_tracked | dirstate_flag_p2_tracked)) ||
849 851 (t->flags &
850 852 (dirstate_flag_possibly_dirty | dirstate_flag_merged))) {
851 853 if (PySet_Add(nonnset, fname) == -1) {
852 854 goto bail;
853 855 }
854 856 }
855 857 }
856 858
857 859 result = Py_BuildValue("(OO)", nonnset, otherpset);
858 860 if (result == NULL) {
859 861 goto bail;
860 862 }
861 863 Py_DECREF(nonnset);
862 864 Py_DECREF(otherpset);
863 865 return result;
864 866 bail:
865 867 Py_XDECREF(nonnset);
866 868 Py_XDECREF(otherpset);
867 869 Py_XDECREF(result);
868 870 return NULL;
869 871 }
870 872
871 873 /*
872 874 * Efficiently pack a dirstate object into its on-disk format.
873 875 */
874 876 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
875 877 {
876 878 PyObject *packobj = NULL;
877 879 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
878 880 Py_ssize_t nbytes, pos, l;
879 881 PyObject *k, *v = NULL, *pn;
880 882 char *p, *s;
881 883 int now;
882 884
883 885 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
884 886 &PyDict_Type, &copymap, &PyTuple_Type, &pl,
885 887 &now)) {
886 888 return NULL;
887 889 }
888 890
889 891 if (PyTuple_Size(pl) != 2) {
890 892 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
891 893 return NULL;
892 894 }
893 895
894 896 /* Figure out how much we need to allocate. */
895 897 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
896 898 PyObject *c;
897 899 if (!PyBytes_Check(k)) {
898 900 PyErr_SetString(PyExc_TypeError, "expected string key");
899 901 goto bail;
900 902 }
901 903 nbytes += PyBytes_GET_SIZE(k) + 17;
902 904 c = PyDict_GetItem(copymap, k);
903 905 if (c) {
904 906 if (!PyBytes_Check(c)) {
905 907 PyErr_SetString(PyExc_TypeError,
906 908 "expected string key");
907 909 goto bail;
908 910 }
909 911 nbytes += PyBytes_GET_SIZE(c) + 1;
910 912 }
911 913 }
912 914
913 915 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
914 916 if (packobj == NULL) {
915 917 goto bail;
916 918 }
917 919
918 920 p = PyBytes_AS_STRING(packobj);
919 921
920 922 pn = PyTuple_GET_ITEM(pl, 0);
921 923 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
922 924 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
923 925 goto bail;
924 926 }
925 927 memcpy(p, s, l);
926 928 p += 20;
927 929 pn = PyTuple_GET_ITEM(pl, 1);
928 930 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
929 931 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
930 932 goto bail;
931 933 }
932 934 memcpy(p, s, l);
933 935 p += 20;
934 936
935 937 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
936 938 dirstateItemObject *tuple;
937 939 char state;
938 940 int mode, size, mtime;
939 941 Py_ssize_t len, l;
940 942 PyObject *o;
941 943 char *t;
942 944
943 945 if (!dirstate_tuple_check(v)) {
944 946 PyErr_SetString(PyExc_TypeError,
945 947 "expected a dirstate tuple");
946 948 goto bail;
947 949 }
948 950 tuple = (dirstateItemObject *)v;
949 951
950 952 state = dirstate_item_c_v1_state(tuple);
951 953 mode = dirstate_item_c_v1_mode(tuple);
952 954 size = dirstate_item_c_v1_size(tuple);
953 955 mtime = dirstate_item_c_v1_mtime(tuple);
954 956 if (state == 'n' && mtime == now) {
955 957 /* See pure/parsers.py:pack_dirstate for why we do
956 958 * this. */
957 959 mtime = -1;
958 960 mtime_unset = (PyObject *)dirstate_item_from_v1_data(
959 961 state, mode, size, mtime);
960 962 if (!mtime_unset) {
961 963 goto bail;
962 964 }
963 965 if (PyDict_SetItem(map, k, mtime_unset) == -1) {
964 966 goto bail;
965 967 }
966 968 Py_DECREF(mtime_unset);
967 969 mtime_unset = NULL;
968 970 }
969 971 *p++ = state;
970 972 putbe32((uint32_t)mode, p);
971 973 putbe32((uint32_t)size, p + 4);
972 974 putbe32((uint32_t)mtime, p + 8);
973 975 t = p + 12;
974 976 p += 16;
975 977 len = PyBytes_GET_SIZE(k);
976 978 memcpy(p, PyBytes_AS_STRING(k), len);
977 979 p += len;
978 980 o = PyDict_GetItem(copymap, k);
979 981 if (o) {
980 982 *p++ = '\0';
981 983 l = PyBytes_GET_SIZE(o);
982 984 memcpy(p, PyBytes_AS_STRING(o), l);
983 985 p += l;
984 986 len += l + 1;
985 987 }
986 988 putbe32((uint32_t)len, t);
987 989 }
988 990
989 991 pos = p - PyBytes_AS_STRING(packobj);
990 992 if (pos != nbytes) {
991 993 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
992 994 (long)pos, (long)nbytes);
993 995 goto bail;
994 996 }
995 997
996 998 return packobj;
997 999 bail:
998 1000 Py_XDECREF(mtime_unset);
999 1001 Py_XDECREF(packobj);
1000 1002 Py_XDECREF(v);
1001 1003 return NULL;
1002 1004 }
1003 1005
1004 1006 #define BUMPED_FIX 1
1005 1007 #define USING_SHA_256 2
1006 1008 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
1007 1009
1008 1010 static PyObject *readshas(const char *source, unsigned char num,
1009 1011 Py_ssize_t hashwidth)
1010 1012 {
1011 1013 int i;
1012 1014 PyObject *list = PyTuple_New(num);
1013 1015 if (list == NULL) {
1014 1016 return NULL;
1015 1017 }
1016 1018 for (i = 0; i < num; i++) {
1017 1019 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
1018 1020 if (hash == NULL) {
1019 1021 Py_DECREF(list);
1020 1022 return NULL;
1021 1023 }
1022 1024 PyTuple_SET_ITEM(list, i, hash);
1023 1025 source += hashwidth;
1024 1026 }
1025 1027 return list;
1026 1028 }
1027 1029
1028 1030 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
1029 1031 uint32_t *msize)
1030 1032 {
1031 1033 const char *data = databegin;
1032 1034 const char *meta;
1033 1035
1034 1036 double mtime;
1035 1037 int16_t tz;
1036 1038 uint16_t flags;
1037 1039 unsigned char nsuccs, nparents, nmetadata;
1038 1040 Py_ssize_t hashwidth = 20;
1039 1041
1040 1042 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
1041 1043 PyObject *metadata = NULL, *ret = NULL;
1042 1044 int i;
1043 1045
1044 1046 if (data + FM1_HEADER_SIZE > dataend) {
1045 1047 goto overflow;
1046 1048 }
1047 1049
1048 1050 *msize = getbe32(data);
1049 1051 data += 4;
1050 1052 mtime = getbefloat64(data);
1051 1053 data += 8;
1052 1054 tz = getbeint16(data);
1053 1055 data += 2;
1054 1056 flags = getbeuint16(data);
1055 1057 data += 2;
1056 1058
1057 1059 if (flags & USING_SHA_256) {
1058 1060 hashwidth = 32;
1059 1061 }
1060 1062
1061 1063 nsuccs = (unsigned char)(*data++);
1062 1064 nparents = (unsigned char)(*data++);
1063 1065 nmetadata = (unsigned char)(*data++);
1064 1066
1065 1067 if (databegin + *msize > dataend) {
1066 1068 goto overflow;
1067 1069 }
1068 1070 dataend = databegin + *msize; /* narrow down to marker size */
1069 1071
1070 1072 if (data + hashwidth > dataend) {
1071 1073 goto overflow;
1072 1074 }
1073 1075 prec = PyBytes_FromStringAndSize(data, hashwidth);
1074 1076 data += hashwidth;
1075 1077 if (prec == NULL) {
1076 1078 goto bail;
1077 1079 }
1078 1080
1079 1081 if (data + nsuccs * hashwidth > dataend) {
1080 1082 goto overflow;
1081 1083 }
1082 1084 succs = readshas(data, nsuccs, hashwidth);
1083 1085 if (succs == NULL) {
1084 1086 goto bail;
1085 1087 }
1086 1088 data += nsuccs * hashwidth;
1087 1089
1088 1090 if (nparents == 1 || nparents == 2) {
1089 1091 if (data + nparents * hashwidth > dataend) {
1090 1092 goto overflow;
1091 1093 }
1092 1094 parents = readshas(data, nparents, hashwidth);
1093 1095 if (parents == NULL) {
1094 1096 goto bail;
1095 1097 }
1096 1098 data += nparents * hashwidth;
1097 1099 } else {
1098 1100 parents = Py_None;
1099 1101 Py_INCREF(parents);
1100 1102 }
1101 1103
1102 1104 if (data + 2 * nmetadata > dataend) {
1103 1105 goto overflow;
1104 1106 }
1105 1107 meta = data + (2 * nmetadata);
1106 1108 metadata = PyTuple_New(nmetadata);
1107 1109 if (metadata == NULL) {
1108 1110 goto bail;
1109 1111 }
1110 1112 for (i = 0; i < nmetadata; i++) {
1111 1113 PyObject *tmp, *left = NULL, *right = NULL;
1112 1114 Py_ssize_t leftsize = (unsigned char)(*data++);
1113 1115 Py_ssize_t rightsize = (unsigned char)(*data++);
1114 1116 if (meta + leftsize + rightsize > dataend) {
1115 1117 goto overflow;
1116 1118 }
1117 1119 left = PyBytes_FromStringAndSize(meta, leftsize);
1118 1120 meta += leftsize;
1119 1121 right = PyBytes_FromStringAndSize(meta, rightsize);
1120 1122 meta += rightsize;
1121 1123 tmp = PyTuple_New(2);
1122 1124 if (!left || !right || !tmp) {
1123 1125 Py_XDECREF(left);
1124 1126 Py_XDECREF(right);
1125 1127 Py_XDECREF(tmp);
1126 1128 goto bail;
1127 1129 }
1128 1130 PyTuple_SET_ITEM(tmp, 0, left);
1129 1131 PyTuple_SET_ITEM(tmp, 1, right);
1130 1132 PyTuple_SET_ITEM(metadata, i, tmp);
1131 1133 }
1132 1134 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
1133 1135 (int)tz * 60, parents);
1134 1136 goto bail; /* return successfully */
1135 1137
1136 1138 overflow:
1137 1139 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
1138 1140 bail:
1139 1141 Py_XDECREF(prec);
1140 1142 Py_XDECREF(succs);
1141 1143 Py_XDECREF(metadata);
1142 1144 Py_XDECREF(parents);
1143 1145 return ret;
1144 1146 }
1145 1147
1146 1148 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
1147 1149 {
1148 1150 const char *data, *dataend;
1149 1151 Py_ssize_t datalen, offset, stop;
1150 1152 PyObject *markers = NULL;
1151 1153
1152 1154 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
1153 1155 &offset, &stop)) {
1154 1156 return NULL;
1155 1157 }
1156 1158 if (offset < 0) {
1157 1159 PyErr_SetString(PyExc_ValueError,
1158 1160 "invalid negative offset in fm1readmarkers");
1159 1161 return NULL;
1160 1162 }
1161 1163 if (stop > datalen) {
1162 1164 PyErr_SetString(
1163 1165 PyExc_ValueError,
1164 1166 "stop longer than data length in fm1readmarkers");
1165 1167 return NULL;
1166 1168 }
1167 1169 dataend = data + datalen;
1168 1170 data += offset;
1169 1171 markers = PyList_New(0);
1170 1172 if (!markers) {
1171 1173 return NULL;
1172 1174 }
1173 1175 while (offset < stop) {
1174 1176 uint32_t msize;
1175 1177 int error;
1176 1178 PyObject *record = fm1readmarker(data, dataend, &msize);
1177 1179 if (!record) {
1178 1180 goto bail;
1179 1181 }
1180 1182 error = PyList_Append(markers, record);
1181 1183 Py_DECREF(record);
1182 1184 if (error) {
1183 1185 goto bail;
1184 1186 }
1185 1187 data += msize;
1186 1188 offset += msize;
1187 1189 }
1188 1190 return markers;
1189 1191 bail:
1190 1192 Py_DECREF(markers);
1191 1193 return NULL;
1192 1194 }
1193 1195
1194 1196 static char parsers_doc[] = "Efficient content parsing.";
1195 1197
1196 1198 PyObject *encodedir(PyObject *self, PyObject *args);
1197 1199 PyObject *pathencode(PyObject *self, PyObject *args);
1198 1200 PyObject *lowerencode(PyObject *self, PyObject *args);
1199 1201 PyObject *parse_index2(PyObject *self, PyObject *args, PyObject *kwargs);
1200 1202
1201 1203 static PyMethodDef methods[] = {
1202 1204 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1203 1205 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
1204 1206 "create a set containing non-normal and other parent entries of given "
1205 1207 "dirstate\n"},
1206 1208 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1207 1209 {"parse_index2", (PyCFunction)parse_index2, METH_VARARGS | METH_KEYWORDS,
1208 1210 "parse a revlog index\n"},
1209 1211 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
1210 1212 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
1211 1213 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
1212 1214 {"dict_new_presized", dict_new_presized, METH_VARARGS,
1213 1215 "construct a dict with an expected size\n"},
1214 1216 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
1215 1217 "make file foldmap\n"},
1216 1218 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
1217 1219 "escape a UTF-8 byte string to JSON (fast path)\n"},
1218 1220 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
1219 1221 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
1220 1222 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
1221 1223 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
1222 1224 "parse v1 obsolete markers\n"},
1223 1225 {NULL, NULL}};
1224 1226
1225 1227 void dirs_module_init(PyObject *mod);
1226 1228 void manifest_module_init(PyObject *mod);
1227 1229 void revlog_module_init(PyObject *mod);
1228 1230
1229 1231 static const int version = 20;
1230 1232
1231 1233 static void module_init(PyObject *mod)
1232 1234 {
1233 1235 PyObject *capsule = NULL;
1234 1236 PyModule_AddIntConstant(mod, "version", version);
1235 1237
1236 1238 /* This module constant has two purposes. First, it lets us unit test
1237 1239 * the ImportError raised without hard-coding any error text. This
1238 1240 * means we can change the text in the future without breaking tests,
1239 1241 * even across changesets without a recompile. Second, its presence
1240 1242 * can be used to determine whether the version-checking logic is
1241 1243 * present, which also helps in testing across changesets without a
1242 1244 * recompile. Note that this means the pure-Python version of parsers
1243 1245 * should not have this module constant. */
1244 1246 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
1245 1247
1246 1248 dirs_module_init(mod);
1247 1249 manifest_module_init(mod);
1248 1250 revlog_module_init(mod);
1249 1251
1250 1252 capsule = PyCapsule_New(
1251 1253 dirstate_item_from_v1_data,
1252 1254 "mercurial.cext.parsers.make_dirstate_item_CAPI", NULL);
1253 1255 if (capsule != NULL)
1254 1256 PyModule_AddObject(mod, "make_dirstate_item_CAPI", capsule);
1255 1257
1256 1258 if (PyType_Ready(&dirstateItemType) < 0) {
1257 1259 return;
1258 1260 }
1259 1261 Py_INCREF(&dirstateItemType);
1260 1262 PyModule_AddObject(mod, "DirstateItem", (PyObject *)&dirstateItemType);
1261 1263 }
1262 1264
1263 1265 static int check_python_version(void)
1264 1266 {
1265 1267 PyObject *sys = PyImport_ImportModule("sys"), *ver;
1266 1268 long hexversion;
1267 1269 if (!sys) {
1268 1270 return -1;
1269 1271 }
1270 1272 ver = PyObject_GetAttrString(sys, "hexversion");
1271 1273 Py_DECREF(sys);
1272 1274 if (!ver) {
1273 1275 return -1;
1274 1276 }
1275 1277 hexversion = PyInt_AsLong(ver);
1276 1278 Py_DECREF(ver);
1277 1279 /* sys.hexversion is a 32-bit number by default, so the -1 case
1278 1280 * should only occur in unusual circumstances (e.g. if sys.hexversion
1279 1281 * is manually set to an invalid value). */
1280 1282 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
1281 1283 PyErr_Format(PyExc_ImportError,
1282 1284 "%s: The Mercurial extension "
1283 1285 "modules were compiled with Python " PY_VERSION
1284 1286 ", but "
1285 1287 "Mercurial is currently using Python with "
1286 1288 "sys.hexversion=%ld: "
1287 1289 "Python %s\n at: %s",
1288 1290 versionerrortext, hexversion, Py_GetVersion(),
1289 1291 Py_GetProgramFullPath());
1290 1292 return -1;
1291 1293 }
1292 1294 return 0;
1293 1295 }
1294 1296
1295 1297 #ifdef IS_PY3K
1296 1298 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
1297 1299 parsers_doc, -1, methods};
1298 1300
1299 1301 PyMODINIT_FUNC PyInit_parsers(void)
1300 1302 {
1301 1303 PyObject *mod;
1302 1304
1303 1305 if (check_python_version() == -1)
1304 1306 return NULL;
1305 1307 mod = PyModule_Create(&parsers_module);
1306 1308 module_init(mod);
1307 1309 return mod;
1308 1310 }
1309 1311 #else
1310 1312 PyMODINIT_FUNC initparsers(void)
1311 1313 {
1312 1314 PyObject *mod;
1313 1315
1314 1316 if (check_python_version() == -1) {
1315 1317 return;
1316 1318 }
1317 1319 mod = Py_InitModule3("parsers", methods, parsers_doc);
1318 1320 module_init(mod);
1319 1321 }
1320 1322 #endif
General Comments 0
You need to be logged in to leave comments. Login now