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