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); |
93 return ret; |
105 return ret; |
94 } |
106 } |
95 |
107 |
96 static int _delpath(PyObject *dirs, PyObject *path) |
108 static int _delpath(PyObject *dirs, PyObject *path) |
97 { |
109 { |
98 Py_ssize_t pos = PyString_GET_SIZE(path); |
110 Py_ssize_t pos = -1; |
99 PyObject *key = NULL; |
111 PyObject *key = NULL; |
100 int ret = -1; |
112 int ret = -1; |
101 |
113 |
102 while ((pos = _finddir(path, pos - 1)) != -1) { |
114 while ((pos = _finddir(path, pos + 1)) != -1) { |
103 PyObject *val; |
115 PyObject *val; |
104 |
116 |
105 key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos); |
117 key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos); |
106 |
118 |
107 if (key == NULL) |
119 if (key == NULL) |