[PATCH 06 of 11 V1] pathencode: add new cutdirs function

Adrian Buehlmann adrian at cadifra.com
Sun Sep 30 16:56:43 CDT 2012


# HG changeset patch
# User Adrian Buehlmann <adrian at cadifra.com>
# Date 1349027010 -7200
# Node ID fe91c34f8b8e384622a3246030ade6d485b5461d
# Parent  e6d3bef190ac0cf58ed69becdb143eb86fc65c16
pathencode: add new cutdirs function

diff --git a/mercurial/parsers.c b/mercurial/parsers.c
--- a/mercurial/parsers.c
+++ b/mercurial/parsers.c
@@ -1508,6 +1508,7 @@
 
 PyObject *encodedir(PyObject *self, PyObject *args);
 PyObject *pathencode(PyObject *self, PyObject *args);
+PyObject *cutdirs(PyObject *self, PyObject *args);
 
 static PyMethodDef methods[] = {
 	{"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
@@ -1516,6 +1517,7 @@
 	{"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
 	{"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
 	{"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
+	{"cutdirs", cutdirs, METH_VARARGS, "fncache-encode a path\n"},
 	{NULL, NULL}
 };
 
diff --git a/mercurial/pathencode.c b/mercurial/pathencode.c
--- a/mercurial/pathencode.c
+++ b/mercurial/pathencode.c
@@ -481,6 +481,92 @@
 
 static const Py_ssize_t maxstorepathlen = 120;
 
+static const char encchar[256] =
+	"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+	"~!~#$%&'()~+,-~~0123456789~;~=~~"
+	"@abcdefghijklmnopqrstuvwxyz[~]^_"
+	"`abcdefghijklmnopqrstuvwxyz{~}~~"
+	"~abcdefghijklmnopqrstuvwxyz{~}~~"
+	"~!~#$%&'()~+,-~~0123456789~;~=~~"
+	"@abcdefghijklmnopqrstuvwxyz[~]^_"
+	"`abcdefghijklmnopqrstuvwxyz{~}~~";
+
+/* this encoding folds */
+static inline char encodechar(char c)
+{
+	return encchar[0xff & c];
+}
+
+static Py_ssize_t _cutdirs(char *dest, Py_ssize_t destlen, size_t destsize,
+                           const char *src, Py_ssize_t len)
+{
+	Py_ssize_t i = 0, spaceleft = maxstorepathlen - 45 + 1;
+	char seg[8];
+	int seglen = 0;
+	uint32_t cmp;
+
+	while (i < len && spaceleft > 0) {
+		if (src[i] == '/' || src[i] == '\0') {
+			if (seglen != 0) {
+				if (seglen == 3) {
+					cmp = seg[0] << 16 | seg[1] << 8 | seg[2];
+					if (   cmp == 0x617578 /* aux */
+					    || cmp == 0x636f6e /* con */
+					    || cmp == 0x70726e /* prn */
+					    || cmp == 0x6e756c /* nul */)
+						seg[2] = '~';
+				}
+				else if (seglen == 4 && seg[3] <= '9'
+				                     && seg[3] >= '0') {
+					cmp = seg[0] << 16 | seg[1] << 8 | seg[2];
+					if (   cmp == 0x636f6d /* com0..9 */
+					    || cmp == 0x6c7074 /* lpt0..9 */)
+						seg[3] = '~';
+				}
+				memcopy(dest, &destlen, destsize, &seg, seglen);
+				seglen = 0;
+			}
+			charcopy(dest, &destlen, destsize, src[i++]);
+			spaceleft--;
+		}
+		else if (seglen == sizeof(seg)) {
+			i++;
+		}
+		else {
+			seg[seglen++] = encodechar(src[i++]);
+			spaceleft--;
+		}
+	}
+
+	return destlen;
+}
+
+PyObject *cutdirs(PyObject *self, PyObject *args)
+{
+	Py_ssize_t len, newlen;
+	PyObject *pathobj, *newobj;
+	char *path;
+
+	if (!PyArg_ParseTuple(args, "O:cutdirs", &pathobj))
+		return NULL;
+
+	if (PyString_AsStringAndSize(pathobj, &path, &len) == -1) {
+		PyErr_SetString(PyExc_TypeError, "expected a string");
+		return NULL;
+	}
+
+	newlen = len ? _cutdirs(NULL, 0, 0, path, len + 1) : 1;
+
+	newobj = PyString_FromStringAndSize(NULL, newlen);
+
+	if (newobj) {
+		PyString_GET_SIZE(newobj)--;
+		_cutdirs(PyString_AS_STRING(newobj), 0, newlen, path, len + 1);
+	}
+
+	return newobj;
+}
+
 /*
  * We currently implement only basic encoding.
  *


More information about the Mercurial-devel mailing list