1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
##############################################################
#
# opendir.pyx - A class exposing the functionality of
# =========== the opendir() family of C libary functions.
#
# By Gregory Ewing
# greg.ewing@canterbury.ac.nz
#
# This software and derivative works created from it
# may be used and redistributed without restriction.
#
##############################################################
cdef extern from "sys/errno.h":
int errno
cdef extern from "stdio.h":
char *strerror(int)
cdef extern from "dirent.h":
ctypedef struct DIR
struct dirent:
int d_namlen
char d_name[1]
DIR *c_opendir "opendir" (char *)
int readdir_r(DIR *, dirent *, dirent **)
long telldir(DIR *)
void seekdir(DIR *, long)
void rewinddir(DIR *)
int closedir(DIR *)
int dirfd(DIR *)
#------------------------------------------------------------------
cdef class opendir:
"""opendir(pathname) --> an open directory object
Opens a directory and provides incremental access to
the filenames it contains. May be used as a file-like
object or as an iterator.
When used as a file-like object, each call to read()
returns one filename, or an empty string when the end
of the directory is reached. The close() method should
be called when finished with the directory.
The close() method should also be called when used as
an iterator and iteration is stopped prematurely. If
iteration proceeds to completion, the directory is
closed automatically."""
cdef DIR *dir
def __cinit__(self, char *path):
self.dir = c_opendir(path)
if not self.dir:
raise IOError(errno, "%s: '%s'" % (strerror(errno), path))
def __dealloc__(self):
if self.dir:
closedir(self.dir)
def read(self):
"""read() --> filename or empty string
Returns the next filename from the directory, or an empty
string if the end of the directory has been reached."""
cdef dirent entry, *result
check_open(self)
if readdir_r(self.dir, &entry, &result) < 0:
raise IOError(errno)
if result:
return entry.d_name
else:
return ""
def tell(self):
"""tell() --> position
Returns a value representing the current position in the
directory, suitable for passing to tell(). Only valid for
this directory object as long as it remains open."""
check_open(self)
return telldir(self.dir)
def seek(self, long pos):
"""seek(position)
Returns the directory to the specified position, which
should be a value previously returned by tell()."""
check_open(self)
seekdir(self.dir, pos)
def rewind(self):
"""rewind()
Resets the position to the beginning of the directory."""
check_open(self)
rewinddir(self.dir)
def close(self):
"""close()
Closes the directory and frees the underlying file descriptor."""
if self.dir:
if closedir(self.dir) < 0:
raise IOError(errno)
self.dir = NULL
# MaxOSX doesn't seem to have dirfd, despite what the
# man page says. :-(
#
# def fileno(self):
# """fileno() --> file descriptor
#
# Returns the file descriptor associated with the open directory."""
#
# check_open(self)
# return dirfd(self.dir)
def __iter__(self):
return self
def __next__(self):
"""next() --> filename
Returns the next filename from the directory. If the end of the
directory has been reached, closes the directory and raises
StopIteration."""
if self.dir:
result = self.read()
if result:
return result
self.close()
raise StopIteration
#------------------------------------------------------------------
cdef int check_open(opendir d) except -1:
if not d.dir:
raise ValueError("Directory is closed")
return 0
|