I had another go at the readdir_r pathconf biz, below, this time actually tested a bit. I'm inclined to use NAME_MAX rather than fpathconf when there's a choice, because NAME_MAX is probably a constant, but I'm open to arguments the other way.
When using pathconf it'd be possible to make the syscall to get the size just once in opendir and store that in the smob (becoming a double cell). Not sure if that's worth doing. The plain readdir() case is protected by a mutex, but I'm wondering if that's really necessary. It could be easier to assume that if you've got posix threads then you've got readdir_r. Likewise with a lot of these choices between plain and "_r" funcs. SCM_DEFINE (scm_readdir, "readdir", 1, 0, 0, (SCM port), "Return (as a string) the next directory entry from the directory stream\n" "@var{stream}. If there is no remaining entry to be read then the\n" "end of file object is returned.") #define FUNC_NAME s_scm_readdir { struct dirent *rdent; SCM_VALIDATE_DIR (1, port); if (!SCM_DIR_OPEN_P (port)) SCM_MISC_ERROR ("Directory ~S is not open.", scm_list_1 (port)); #if HAVE_READDIR_R { DIR *ds = (DIR *) SCM_CELL_WORD_1 (port); struct dirent de; /* just for sizeof */ size_t name_max, dirent_size, namlen; char *buf; int old_errno; /* On solaris 10 there's no NAME_MAX constant, it's obligatory to use pathconf(). */ #ifdef NAME_MAX name_max = NAME_MAX; #else name_max = fpathconf (dirfd (ds), _PC_NAME_MAX); if (name_max == -1) SCM_SYSERROR; #endif /* As noted in the glibc manual, on various systems (such as Solaris) the d_name[] field is only 1 char and you're expected to size the buffer for readdir_r based on NAME_MAX. So the following effectively uses the bigger of sizeof(d_name) or NAME_MAX. */ dirent_size = SCM_MAX (sizeof (de), sizeof (de) - sizeof (de.d_name) + name_max + 1); /* NAME_MAX is typically 255, so alloca on the stack is good */ buf = alloca (dirent_size); errno = 0; SCM_SYSCALL (readdir_r (ds, (struct dirent *) buf, &rdent)); if (errno != 0) SCM_SYSERROR; if (! rdent) return SCM_EOF_VAL; namlen = NAMLEN (rdent); return (rdent ? scm_from_locale_stringn (rdent->d_name, NAMLEN (rdent)) : SCM_EOF_VAL); } #else { SCM ret; scm_dynwind_begin (0); scm_i_dynwind_pthread_mutex_lock (&scm_i_misc_mutex); errno = 0; SCM_SYSCALL (rdent = readdir ((DIR *) SCM_CELL_WORD_1 (port))); if (errno != 0) SCM_SYSERROR; ret = (rdent ? scm_from_locale_stringn (rdent->d_name, NAMLEN (rdent)) : SCM_EOF_VAL); scm_dynwind_end (); return ret; } #endif } #undef FUNC_NAME _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel