diff options
Diffstat (limited to 'packages/python/python-opendir/opendir.pyx')
-rw-r--r-- | packages/python/python-opendir/opendir.pyx | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/packages/python/python-opendir/opendir.pyx b/packages/python/python-opendir/opendir.pyx new file mode 100644 index 0000000000..1ee81f7382 --- /dev/null +++ b/packages/python/python-opendir/opendir.pyx @@ -0,0 +1,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 + |