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