mercurial/dirs.c
changeset 24486 1a9efc312700
parent 23960 bca4b6f126f2
child 24624 6f0e6fa9fdd7
equal deleted inserted replaced
24485:914caae9a86a 24486:1a9efc312700
     7  the GNU General Public License, incorporated herein by reference.
     7  the GNU General Public License, incorporated herein by reference.
     8 */
     8 */
     9 
     9 
    10 #define PY_SSIZE_T_CLEAN
    10 #define PY_SSIZE_T_CLEAN
    11 #include <Python.h>
    11 #include <Python.h>
       
    12 #include <string.h>
    12 #include "util.h"
    13 #include "util.h"
    13 
    14 
    14 /*
    15 /*
    15  * This is a multiset of directory names, built from the files that
    16  * This is a multiset of directory names, built from the files that
    16  * appear in a dirstate or manifest.
    17  * appear in a dirstate or manifest.
    30 
    31 
    31 static inline Py_ssize_t _finddir(PyObject *path, Py_ssize_t pos)
    32 static inline Py_ssize_t _finddir(PyObject *path, Py_ssize_t pos)
    32 {
    33 {
    33 	const char *s = PyString_AS_STRING(path);
    34 	const char *s = PyString_AS_STRING(path);
    34 
    35 
    35 	while (pos != -1) {
    36 	const char *ret = strchr(s + pos, '/');
    36 		if (s[pos] == '/')
    37 	return (ret != NULL) ? (ret - s) : -1;
    37 			break;
       
    38 		pos -= 1;
       
    39 	}
       
    40 
       
    41 	return pos;
       
    42 }
    38 }
    43 
    39 
    44 static int _addpath(PyObject *dirs, PyObject *path)
    40 static int _addpath(PyObject *dirs, PyObject *path)
    45 {
    41 {
    46 	const char *cpath = PyString_AS_STRING(path);
    42 	char *cpath = PyString_AS_STRING(path);
    47 	Py_ssize_t pos = PyString_GET_SIZE(path);
    43 	Py_ssize_t len = PyString_GET_SIZE(path);
       
    44 	Py_ssize_t pos = -1;
    48 	PyObject *key = NULL;
    45 	PyObject *key = NULL;
    49 	int ret = -1;
    46 	int ret = -1;
    50 
    47 
    51 	while ((pos = _finddir(path, pos - 1)) != -1) {
    48 	while ((pos = _finddir(path, pos + 1)) != -1) {
    52 		PyObject *val;
    49 		PyObject *val;
    53 
    50 
    54 		/* It's likely that every prefix already has an entry
    51 		/* It's likely that every prefix already has an entry
    55 		   in our dict. Try to avoid allocating and
    52 		   in our dict. Try to avoid allocating and
    56 		   deallocating a string for each prefix we check. */
    53 		   deallocating a string for each prefix we check. */
    57 		if (key != NULL)
    54 		if (key != NULL)
    58 			((PyStringObject *)key)->ob_shash = -1;
    55 			((PyStringObject *)key)->ob_shash = -1;
    59 		else {
    56 		else if (pos != 0) {
    60 			/* Force Python to not reuse a small shared string. */
    57 			/* pos >= 1, which means that len >= 2. This is
    61 			key = PyString_FromStringAndSize(cpath,
    58 			   guaranteed to produce a non-interned string. */
    62 							 pos < 2 ? 2 : pos);
    59 			key = PyString_FromStringAndSize(cpath, len);
       
    60 			if (key == NULL)
       
    61 				goto bail;
       
    62 		} else {
       
    63 			/* pos == 0, which means we need to increment the dir
       
    64 			   count for the empty string. We need to make sure we
       
    65 			   don't muck around with interned strings, so throw it
       
    66 			   away later. */
       
    67 			key = PyString_FromString("");
    63 			if (key == NULL)
    68 			if (key == NULL)
    64 				goto bail;
    69 				goto bail;
    65 		}
    70 		}
    66 		PyString_GET_SIZE(key) = pos;
    71 		PyString_GET_SIZE(key) = pos;
    67 		PyString_AS_STRING(key)[pos] = '\0';
    72 		PyString_AS_STRING(key)[pos] = '\0';
    68 
    73 
    69 		val = PyDict_GetItem(dirs, key);
    74 		val = PyDict_GetItem(dirs, key);
    70 		if (val != NULL) {
    75 		if (val != NULL) {
    71 			PyInt_AS_LONG(val) += 1;
    76 			PyInt_AS_LONG(val) += 1;
       
    77 			if (pos != 0)
       
    78 				PyString_AS_STRING(key)[pos] = '/';
       
    79 			else
       
    80 				key = NULL;
    72 			continue;
    81 			continue;
    73 		}
    82 		}
    74 
    83 
    75 		/* Force Python to not reuse a small shared int. */
    84 		/* Force Python to not reuse a small shared int. */
    76 		val = PyInt_FromLong(0x1eadbeef);
    85 		val = PyInt_FromLong(0x1eadbeef);
    81 		PyInt_AS_LONG(val) = 1;
    90 		PyInt_AS_LONG(val) = 1;
    82 		ret = PyDict_SetItem(dirs, key, val);
    91 		ret = PyDict_SetItem(dirs, key, val);
    83 		Py_DECREF(val);
    92 		Py_DECREF(val);
    84 		if (ret == -1)
    93 		if (ret == -1)
    85 			goto bail;
    94 			goto bail;
       
    95 
       
    96 		if (pos != 0)
       
    97 			PyString_AS_STRING(key)[pos] = '/';
       
    98 		else
       
    99 			key = NULL;
    86 		Py_CLEAR(key);
   100 		Py_CLEAR(key);
    87 	}
   101 	}
    88 	ret = 0;
   102 	ret = 0;
    89 
   103 
    90 bail:
   104 bail:
    93 	return ret;
   107 	return ret;
    94 }
   108 }
    95 
   109 
    96 static int _delpath(PyObject *dirs, PyObject *path)
   110 static int _delpath(PyObject *dirs, PyObject *path)
    97 {
   111 {
    98 	Py_ssize_t pos = PyString_GET_SIZE(path);
   112 	Py_ssize_t pos = -1;
    99 	PyObject *key = NULL;
   113 	PyObject *key = NULL;
   100 	int ret = -1;
   114 	int ret = -1;
   101 
   115 
   102 	while ((pos = _finddir(path, pos - 1)) != -1) {
   116 	while ((pos = _finddir(path, pos + 1)) != -1) {
   103 		PyObject *val;
   117 		PyObject *val;
   104 
   118 
   105 		key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos);
   119 		key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos);
   106 
   120 
   107 		if (key == NULL)
   121 		if (key == NULL)