/* opendir/readdir/closedir routines */ /* under MiNT (v0.9 or better) these use the appropriate system calls. * under TOS or older versions of MiNT, they use Fsfirst/Fsnext * * Written by Eric R. Smith and placed in the public domain */ #include #include #include #include #include #include #include #include #include "lib.h" extern int __mint; extern ino_t __inode; /* in stat.c */ DIR * opendir(uname) const char *uname; { DIR *d; long r, olddta; char name[PATH_MAX]; char dirpath[PATH_MAX]; _unx2dos(uname, name); if (__mint > 8) { r = Dopendir(name, 0); if ( (r & 0xff000000) == 0xff000000 ) { errno = -r; return 0; } return (DIR *)r; } /* TOS emulation routines */ d = malloc(sizeof(DIR)); if (!d) { errno = ENOMEM; return d; } strcat(name, "\\*.*"); olddta = Fgetdta(); Fsetdta(d->dta); r = Fsfirst(name, 0xff); Fsetdta(olddta); if (r == 0) { d->status = _STARTSEARCH; } else if (r == -ENOENT) { d->status = _NMFILE; } else { free(d); errno = -r; return 0; } d->buf.d_off = 0; /* for rewinddir: if necessary, build a relative path */ if (name[1] == ':') { /* absolute path, no problem */ dirpath[0] = 0; } else { dirpath[0] = Dgetdrv() + 'A'; dirpath[1] = ':'; dirpath[2] = 0; if (*name != '\\') (void)Dgetpath(dirpath+2, 0); } d->dirname = malloc(strlen(dirpath)+strlen(name)+1); if (d->dirname) { strcpy(d->dirname, dirpath); strcat(d->dirname, name); } return d; } struct dirent * readdir(d) DIR *d; { struct dbuf { long ino; char name[NAME_MAX + 1]; } dbuf; long r, olddta; struct dirent *dd = &d->buf; if (__mint > 8) { r = Dreaddir(NAME_MAX+1+sizeof(long), d, &dbuf); if (r == -ENMFIL) return 0; else if (r) { errno = -r; return 0; } dd->d_ino = dbuf.ino; dd->d_off++; dd->d_reclen = strlen(dbuf.name); strcpy(dd->d_name, dbuf.name); return dd; } /* ordinary TOS search, using Fsnext. Note that the first time through, * Fsfirst has already provided valid data for us; for subsequent * searches, we need Fsnext. */ if (d->status == _NMFILE) return 0; if (d->status == _STARTSEARCH) { d->status = _INSEARCH; } else { olddta = Fgetdta(); Fsetdta(&d->dta); r = Fsnext(); Fsetdta(olddta); if (r == -ENMFIL) { d->status = _NMFILE; return 0; } else if (r) { errno = -r; return 0; } } dd->d_ino = __inode++; dd->d_off++; _dos2unx(d->dta+30, dd->d_name); dd->d_reclen = strlen(dd->d_name); return dd; } void rewinddir(dirp) DIR *dirp; { long r, olddta; if (__mint >= 9) { (void)Drewinddir(dirp); return; } /* I wish POSIX had allowed an error to occur here! */ if (!dirp->dirname) { return; } olddta = Fgetdta(); Fsetdta(dirp->dta); r = Fsfirst(dirp->dirname, 0xff); Fsetdta(olddta); if (r == 0) { dirp->status = _STARTSEARCH; } else { dirp->status = _NMFILE; } dirp->buf.d_off = 0; } int closedir(dirp) DIR *dirp; { if (__mint > 8) { return Dclosedir(dirp); } free(dirp); return 0; } /* the next two aren't POSIX, but lots of people have them */ off_t telldir(dirp) DIR *dirp; { return dirp->buf.d_off; } void seekdir(dirp, loc) DIR *dirp; off_t loc; { rewinddir(dirp); while (dirp->buf.d_off != loc) { if (!readdir(dirp)) break; } }