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