comparison mercurial/parsers.c @ 7093:16bafcebd3d1

dirstate: C parsing extension
author Matt Mackall <mpm@selenic.com>
date Sun, 12 Oct 2008 15:21:08 -0500
parents fb3fc27617a2
children 1ca878d7b849
comparison
equal deleted inserted replaced
7092:fb3fc27617a2 7093:16bafcebd3d1
126 goto quit; 126 goto quit;
127 } 127 }
128 128
129 Py_INCREF(Py_None); 129 Py_INCREF(Py_None);
130 return Py_None; 130 return Py_None;
131
132 quit: 131 quit:
133 return NULL; 132 return NULL;
134 } 133 }
135 134
135 #ifdef _WIN32
136 # ifdef _MSC_VER
137 /* msvc 6.0 has problems */
138 # define inline __inline
139 typedef unsigned long uint32_t;
140 # else
141 # include <stdint.h>
142 # endif
143 static uint32_t ntohl(uint32_t x)
144 {
145 return ((x & 0x000000ffUL) << 24) |
146 ((x & 0x0000ff00UL) << 8) |
147 ((x & 0x00ff0000UL) >> 8) |
148 ((x & 0xff000000UL) >> 24);
149 }
150 #else
151 /* not windows */
152 # include <sys/types.h>
153 # if defined __BEOS__ && !defined __HAIKU__
154 # include <ByteOrder.h>
155 # else
156 # include <arpa/inet.h>
157 # endif
158 # include <inttypes.h>
159 #endif
160
161 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
162 {
163 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
164 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
165 char *str, *cur, *end, *cpos;
166 int state, mode, size, mtime, flen;
167 int len;
168 char decode[16]; /* for alignment */
169
170 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
171 &PyDict_Type, &dmap,
172 &PyDict_Type, &cmap,
173 &str, &len))
174 goto quit;
175
176 /* read parents */
177 if (len < 40)
178 goto quit;
179
180 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
181 if (!parents)
182 goto quit;
183
184 /* read filenames */
185 cur = str + 40;
186 end = str + len;
187
188 while (cur < end - 17) {
189 /* unpack header */
190 state = *cur;
191 memcpy(decode, cur + 1, 16);
192 mode = ntohl(*(uint32_t *)(decode));
193 size = ntohl(*(uint32_t *)(decode + 4));
194 mtime = ntohl(*(uint32_t *)(decode + 8));
195 flen = ntohl(*(uint32_t *)(decode + 12));
196 cur += 17;
197 if (cur + flen > end)
198 goto quit;
199
200 entry = Py_BuildValue("ciii", state, mode, size, mtime);
201 PyObject_GC_UnTrack(entry); /* don't waste time with this */
202 if (!entry)
203 goto quit;
204
205 cpos = memchr(cur, 0, flen);
206 if (cpos) {
207 fname = PyString_FromStringAndSize(cur, cpos - cur);
208 cname = PyString_FromStringAndSize(cpos + 1,
209 flen - (cpos - cur) - 1);
210 if (!fname || !cname ||
211 PyDict_SetItem(cmap, fname, cname) == -1 ||
212 PyDict_SetItem(dmap, fname, entry) == -1)
213 goto quit;
214 Py_DECREF(cname);
215 } else {
216 fname = PyString_FromStringAndSize(cur, flen);
217 if (!fname ||
218 PyDict_SetItem(dmap, fname, entry) == -1)
219 goto quit;
220 }
221 cur += flen;
222 Py_DECREF(fname);
223 Py_DECREF(entry);
224 fname = cname = entry = NULL;
225 }
226
227 ret = parents;
228 Py_INCREF(ret);
229 quit:
230 Py_XDECREF(fname);
231 Py_XDECREF(cname);
232 Py_XDECREF(entry);
233 Py_XDECREF(parents);
234 return ret;
235 }
236
136 static char parsers_doc[] = "Efficient content parsing."; 237 static char parsers_doc[] = "Efficient content parsing.";
137 238
138 static PyMethodDef methods[] = { 239 static PyMethodDef methods[] = {
139 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"}, 240 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
241 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
140 {NULL, NULL} 242 {NULL, NULL}
141 }; 243 };
142 244
143 PyMODINIT_FUNC initparsers(void) 245 PyMODINIT_FUNC initparsers(void)
144 { 246 {