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