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