50
50
char *strchr(char *s1, char c)
51
51
int strncmp(char *s1, char *s2, int len)
52
52
int strcmp(char *s1, char *s2)
53
void *memchr(void *s, int c, size_t len)
54
int memcmp(void *b1, void *b2, size_t len)
55
# ??? memrchr is a GNU extension :(
56
# void *memrchr(void *s, int c, size_t len)
59
cdef void* _my_memrchr(void *s, int c, size_t n):
60
# memrchr seems to be a GNU extension, so we have to implement it ourselves
61
# We semi-cheat, and just call memchr repeatedly until we run out of path.
62
# And then return the last match.
68
end = <void*>((<char*>s) + n)
70
while pos != NULL and pos < end:
72
pos = memchr(pos+1, c, end-pos)
76
def _py_memrchr(s, c):
77
"""Just to expose _my_memrchr for testing.
79
:param s: The Python string to search
80
:param c: The character to search for
81
:return: The offset to the last instance of 'c' in s
88
_s = PyString_AsString(s)
89
length = PyString_Size(s)
91
_c = PyString_AsString(c)
92
assert PyString_Size(c) == 1,\
93
'Must be a single character string, not %s' % (c,)
94
found = _my_memrchr(_s, _c[0], length)
55
100
cdef int _cmp_by_dirs(char *path1, int size1, char *path2, int size2):
135
180
PyString_Size(path2))
183
def cmp_path_by_dirblock_c(path1, path2):
184
"""Compare two paths based on what directory they are in.
186
This generates a sort order, such that all children of a directory are
187
sorted together, and grandchildren are in the same order as the
188
children appear. But all grandchildren come after all children.
190
:param path1: first path
191
:param path2: the second path
192
:return: positive number if ``path1`` comes first,
194
and a negative number if ``path2`` sorts first
196
return _cmp_path_by_dirblock(PyString_AsString(path1),
197
PyString_Size(path1),
198
PyString_AsString(path2),
199
PyString_Size(path2))
202
cdef _cmp_path_by_dirblock(char *path1, int path1_len,
203
char *path2, int path2_len):
205
cdef int dirname1_len
207
cdef int dirname2_len
209
cdef int basename1_len
211
cdef int basename2_len
216
dirname1_len = path1_len
219
dirname2_len = path2_len
221
if path1_len == 0 and path2_len == 0:
230
basename1 = <char*>_my_memrchr(dirname1, c'/', dirname1_len)
232
if basename1 == NULL:
237
cur_len = basename1 - dirname1
238
basename1 = basename1 + 1
239
basename1_len = dirname1_len - cur_len - 1
240
dirname1_len = cur_len
242
basename2 = <char*>_my_memrchr(dirname2, c'/', dirname2_len)
244
if basename2 == NULL:
249
cur_len = basename2 - dirname2
250
basename2 = basename2 + 1
251
basename2_len = dirname2_len - cur_len - 1
252
dirname2_len = cur_len
254
cmp_val = _cmp_by_dirs(dirname1, dirname1_len,
255
dirname2, dirname2_len)
259
cur_len = basename1_len
260
if basename2_len < basename1_len:
261
cur_len = basename2_len
263
cmp_val = memcmp(basename1, basename2, cur_len)
266
if basename1_len == basename2_len:
268
if basename1_len < basename2_len:
273
def bisect_path_left_c(paths, path):
274
"""Return the index where to insert path into paths.
276
This uses a path-wise comparison so we get::
286
:param paths: A list of paths to search through
287
:param path: A single path to insert
288
:return: An offset where 'path' can be inserted.
289
:seealso: bisect.bisect_left
300
if not PyList_CheckExact(paths):
301
raise TypeError('you must pass a python list for paths')
302
if not PyString_CheckExact(path):
303
raise TypeError('you must pass a string for path')
308
path_str = PyString_AsString(path)
309
path_size = PyString_Size(path)
312
_mid = (_lo + _hi) / 2
313
cur = PyList_GetItem_object_void(paths, _mid)
314
cur_str = PyString_AS_STRING_void(cur)
315
cur_size = PyString_GET_SIZE_void(cur)
316
if _cmp_path_by_dirblock(cur_str, cur_size, path_str, path_size) < 0:
323
def bisect_path_right_c(paths, path):
324
"""Return the index where to insert path into paths.
326
This uses a path-wise comparison so we get::
336
:param paths: A list of paths to search through
337
:param path: A single path to insert
338
:return: An offset where 'path' can be inserted.
339
:seealso: bisect.bisect_right
351
if not PyList_CheckExact(paths):
352
raise TypeError('you must pass a python list for paths')
353
if not PyString_CheckExact(path):
354
raise TypeError('you must pass a string for path')
359
path_str = PyString_AsString(path)
360
path_size = PyString_Size(path)
363
_mid = (_lo + _hi) / 2
364
cur = PyList_GetItem_object_void(paths, _mid)
365
cur_str = PyString_AS_STRING_void(cur)
366
cur_size = PyString_GET_SIZE_void(cur)
367
cmp_val = _cmp_path_by_dirblock(path_str, path_size, cur_str, cur_size)
368
print 'c_left mid: %d, cmp_val %d, cur_str %r, path_str %r' % (
370
PyString_FromStringAndSize(cur_str, cur_size),
371
PyString_FromStringAndSize(path_str, path_size))
138
379
def bisect_dirblock_c(dirblocks, dirname, lo=0, hi=None, cache=None):
139
380
"""Return the index where to insert dirname into the dirblocks.