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