/** A replacement for os.listdir(). dirlister.listdir(path) returns a generator instead of a list. This was meant to be a more efficient base for tree walkers. It doesn't seem to pay off in practice, but here is the idea anyway. Listing a directory d requires access to two different portions of the disk: the directory entry (call it e) in the parent's directory, and the entries of d itself as a sequence s of entries. The two are typically located at different physical locations. The generator returned by dirlister.listdir() contains an opened directory handle. Opening it should only require access to the directory entry e. On the other hand, walking the generator only requires access to the directory content s. Thus it seemed like a good idea to open the directory entries e while we walked the parent directory, even if the content s is only read later, in code like: def walk(dirgen): subdirgens = [] for entry in dirgen: subdirgens.append(dirlister.listdir(entry)) for subdirgen in subdirgens: walk(subdirgen) **/ #include #ifdef HAVE_DIRENT_H #include #define NAMLEN(dirent) strlen((dirent)->d_name) #else #if defined(__WATCOMC__) && !defined(__QNX__) #include #define NAMLEN(dirent) strlen((dirent)->d_name) #else #define dirent direct #define NAMLEN(dirent) (dirent)->d_namlen #endif #ifdef HAVE_SYS_NDIR_H #include #endif #ifdef HAVE_SYS_DIR_H #include #endif #ifdef HAVE_NDIR_H #include #endif #endif typedef struct { PyObject_HEAD DIR *dirp; } listdirobject; static void listdir_dealloc(listdirobject *self) { DIR* dirp = self->dirp; if (dirp) { Py_BEGIN_ALLOW_THREADS closedir(dirp); Py_END_ALLOW_THREADS } PyObject_Del(self); } static PyObject * listdir_iternext(listdirobject *self) { struct dirent *ep; DIR* dirp = self->dirp; if (!dirp) return NULL; Py_BEGIN_ALLOW_THREADS do { if ((ep = readdir(dirp)) == NULL) { closedir(dirp); dirp = NULL; break; } } while (ep->d_name[0] == '.' && (NAMLEN(ep) == 1 || (ep->d_name[1] == '.' && NAMLEN(ep) == 2))); Py_END_ALLOW_THREADS if (dirp == NULL) { self->dirp = NULL; return NULL; } return PyString_FromStringAndSize(ep->d_name, NAMLEN(ep)); } static PyObject * iter_getiter(PyObject *it) { Py_INCREF(it); return it; } static PyObject * listdir_next(listdirobject *self) { PyObject *result = listdir_iternext(self); if (result == NULL && !PyErr_Occurred()) { PyErr_SetObject(PyExc_StopIteration, Py_None); } return result; } static PyObject * listdir_close(listdirobject *self) { DIR* dirp = self->dirp; if (dirp) { self->dirp = NULL; Py_BEGIN_ALLOW_THREADS closedir(dirp); Py_END_ALLOW_THREADS } Py_INCREF(Py_None); return Py_None; } static PyMethodDef listdir_methods[] = { {"next", (PyCFunction)listdir_next, METH_NOARGS }, {"close", (PyCFunction)listdir_close, METH_NOARGS }, {NULL, NULL} /* sentinel */ }; static PyTypeObject PyListDir_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, /* ob_size */ "listdir-generator", /* tp_name */ sizeof(listdirobject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)listdir_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)iter_getiter, /* tp_iter */ (iternextfunc)listdir_iternext, /* tp_iternext */ listdir_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ }; static PyObject * listdir(PyObject *self, PyObject *args) { listdirobject *d; char *name; DIR *dirp; if (!PyArg_ParseTuple(args, "s:listdir", &name)) return NULL; Py_BEGIN_ALLOW_THREADS dirp = opendir(name); Py_END_ALLOW_THREADS if (dirp == NULL) { return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name); } d = PyObject_New(listdirobject, &PyListDir_Type); if (d == NULL) { closedir(dirp); return NULL; } d->dirp = dirp; return (PyObject*) d; } static PyMethodDef DirListerMethods[] = { {"listdir", listdir, METH_VARARGS}, {NULL, NULL} /* Sentinel */ }; void initdirlister(void) { Py_InitModule("dirlister", DirListerMethods); }