/* PerlIO::dir */ #include "perlioutil.h" #define Dirp(f) (PerlIOSelf(f, PerlIODir)->dirp) #define DirBuf(f) (PerlIOSelf(f, PerlIODir)->buf) #define DirBufPtr(f) (PerlIOSelf(f, PerlIODir)->ptr) #define DirBufEnd(f) (PerlIOSelf(f, PerlIODir)->end) #if defined(FILENAME_MAX) # define DIR_BUFSIZ (FILENAME_MAX+1) #else # define DIR_BUFSIZ 512 #endif /* BUF: foobar\n@@@@@@@@@@@@@ ^ ^ ^ ptr end BUFSIZ */ typedef struct{ struct _PerlIO base; DIR* dirp; STDCHAR buf[DIR_BUFSIZ]; STDCHAR* ptr; STDCHAR* end; } PerlIODir; static PerlIO* PerlIODir_open(pTHX_ PerlIO_funcs* self, PerlIO_list_t* layers, IV n, const char* mode, int fd, int imode, int perm, PerlIO* f, int narg, SV** args){ PERL_UNUSED_ARG(layers); PERL_UNUSED_ARG(n); PERL_UNUSED_ARG(fd); PERL_UNUSED_ARG(imode); PERL_UNUSED_ARG(perm); PERL_UNUSED_ARG(narg); #ifndef EACCES #define EACCES EPERM #endif if(!imode){ imode = PerlIOUnix_oflags(mode); } if( imode & (O_WRONLY | O_RDWR) ){ SETERRNO(EACCES, RMS_PRV); return NULL; } if(PerlIOValid(f)){ /* reopen */ PerlIO_close(f); } else{ f = PerlIO_allocate(aTHX); } return PerlIO_push(aTHX_ f, self, mode, args[0]); } static IV PerlIODir_pushed(pTHX_ PerlIO* f, const char* mode, SV* arg, PerlIO_funcs* tab){ if(!SvOK(arg)){ SETERRNO(EINVAL, LIB_INVARG); return -1; } Dirp(f) = PerlDir_open(SvPV_nolen_const(arg)); if(!Dirp(f)){ return -1; } DirBufPtr(f) = DirBufEnd(f) = DirBuf(f); PerlIOBase(f)->flags |= (PERLIO_F_NOTREG | PERLIO_F_OPEN); return PerlIOBase_pushed(aTHX_ f, mode, arg, tab); } static IV PerlIODir_popped(pTHX_ PerlIO* f){ if(Dirp(f)){ #ifdef VOID_CLOSEDIR PerlDir_close(Dirp(f)); #else if(PerlDir_close(Dirp(f)) < 0){ Dirp(f) = NULL; return -1; } #endif Dirp(f) = NULL; } return PerlIOBase_popped(aTHX_ f); } static IV PerlIODir_fill(pTHX_ PerlIO* f){ #if !defined(I_DIRENT) && !defined(VMS) Direntry_t *readdir (DIR *); #endif const Direntry_t* de = PerlDir_read(Dirp(f)); if(de){ #ifdef DIRNAMLEN STRLEN len = de->d_namlen; #else STRLEN len = strlen(de->d_name); #endif assert(DIR_BUFSIZ > len); Copy(de->d_name, DirBuf(f), len, STDCHAR); /* add "\n" */ DirBuf(f)[len] = '\n'; DirBufPtr(f) = DirBuf(f); DirBufEnd(f) = DirBuf(f) + (len+1); IOLflag_on(f, PERLIO_F_RDBUF); return 0; } else{ IOLflag_off(f, PERLIO_F_RDBUF); IOLflag_on(f, PERLIO_F_EOF); DirBufPtr(f) = DirBufEnd(f) = DirBuf(f); return -1; } } static STDCHAR * PerlIODir_get_base(pTHX_ PerlIO * f){ PERL_UNUSED_CONTEXT; return DirBuf(f); } static STDCHAR * PerlIODir_get_ptr(pTHX_ PerlIO * f){ PERL_UNUSED_CONTEXT; return DirBufPtr(f); } static SSize_t PerlIODir_get_cnt(pTHX_ PerlIO * f){ PERL_UNUSED_CONTEXT; return DirBufEnd(f) - DirBufPtr(f); } static Size_t PerlIODir_bufsiz(pTHX_ PerlIO * f){ PERL_UNUSED_CONTEXT; PERL_UNUSED_ARG(f); return DirBufEnd(f) - DirBuf(f); } static void PerlIODir_set_ptrcnt(pTHX_ PerlIO * f, STDCHAR * ptr, SSize_t cnt){ PERL_UNUSED_CONTEXT; PERL_UNUSED_ARG(cnt); DirBufPtr(f) = ptr; } #if 0 static IV PerlIODir_seek(pTHX_ PerlIO* f, Off_t offset, int whence){ switch(whence){ case SEEK_SET: PerlDir_seek(Dirp(f), offset); break; case SEEK_CUR: if(offset != 0){ goto einval; } break; case SEEK_END: if(offset != 0){ goto einval; } while(PerlDir_read(Dirp(f)) != NULL){ NOOP; } break; default: einval: SETERRNO(EINVAL, LIB_INVARG); return -1; } DirBufPtr(f) = DirBufEnd(f) = DirBuf(f); IOLflag_off(f, PERLIO_F_EOF | PERLIO_F_RDBUF); return 0; } static Off_t PerlIODir_tell(pTHX_ PerlIO* f){ return PerlDir_tell( Dirp(f) ); } #else static IV PerlIODir_seek(pTHX_ PerlIO* f, Off_t offset, int whence){ switch(whence){ case SEEK_SET: if(offset == 0){ PerlDir_rewind(Dirp(f)); return 0; } case SEEK_CUR: case SEEK_END: default: SETERRNO(EINVAL, LIB_INVARG); return -1; } } #define PerlIODir_tell NULL #endif PERLIO_FUNCS_DECL(PerlIO_dir) = { sizeof(PerlIO_funcs), "dir", sizeof(PerlIODir), PERLIO_K_BUFFERED | PERLIO_K_RAW | PERLIO_K_DESTRUCT, PerlIODir_pushed, PerlIODir_popped, PerlIODir_open, PerlIOBase_binmode, NULL, /* getarg */ NULL, /* fileno */ NULL, /* dup */ NULL, /* read */ NULL, /* unread */ NULL, /* write */ PerlIODir_seek, PerlIODir_tell, NULL, /* close */ NULL, /* flush */ PerlIODir_fill, NULL, /* eof */ NULL, /* error */ NULL, /* clearerror */ NULL, /* setlinebuf */ PerlIODir_get_base, PerlIODir_bufsiz, PerlIODir_get_ptr, PerlIODir_get_cnt, PerlIODir_set_ptrcnt };