ng            len;
    long            idx;
    char            scannamespc[PATHLEN];
    char	   *scanname = scannamespc;
    struct stat	    sbuf;
    struct _finddata_t fd;
    long               fh;
    char            root[PATHLEN];
    char            volname[PATHLEN];
    DWORD           serial, maxname, flags;

    //
    // check to see if we\'ve got a directory
    //

    if ((win32_stat (filename, &sbuf) < 0 ||
	sbuf.st_mode & _S_IFDIR == 0) &&
	(!ISALPHA(filename[0]) || filename[1] != ':' || filename[2] != '\0' ||
	((1 << (filename[0] & 0x5f) - 'A') & GetLogicalDrives()) == 0)) {
	return NULL;
    }

    //
    // Get us a DIR structure
    //

    p = xcalloc(sizeof(DIR), 1);
    if (p == NULL)
	return NULL;
    
    //
    // Create the search pattern
    //

    strcpy(scanname, filename);

    if (index("/\\:", *CharPrev(scanname, scanname + strlen(scanname))) == NULL)
	strcat(scanname, "/*");
    else
	strcat(scanname, "*");

    //
    // do the FindFirstFile call
    //

    fh = _findfirst(scanname, &fd);
    if (fh == -1) {
	return NULL;
    }

    //
    // now allocate the first part of the string table for the
    // filenames that we find.
    //

    idx = strlen(fd.name)+1;
    p->start = ALLOC_N(char, idx);
    strcpy(p->start, fd.name);
    p->nfiles++;
    
    //
    // loop finding all the files that match the wildcard
    // (which should be all of them in this directory!).
    // the variable idx should point one past the null terminator
    // of the previous string found.
    //
    while (_findnext(fh, &fd) == 0) {
	len = strlen(fd.name);

	//
	// bump the string table size by enough for the
	// new name and it's null terminator 
	//

	#define Renew(x, y, z) (x = (z *)realloc(x, y))

	Renew (p->start, idx+len+1, char);
	if (p->start == NULL) {
            rb_fatal ("opendir: malloc failed!\n");
	}
	strcpy(&p->start[idx], fd.name);
	p->nfiles++;
	idx += len+1;
    }
    _findclose(fh);
    p->size = idx;
    p->curr = p->start;
    return p;
}


//
// Readdir just returns the current string pointer and bumps the
// string pointer to the next entry.
//

struct direct  *
readdir(DIR *dirp)
{
    int         len;
    static int  dummy = 0;

    if (dirp->curr) {

	//
	// first set up the structure to return
	//

	len = strlen(dirp->curr);
	strcpy(dirp->dirstr.d_name, dirp->curr);
	dirp->dirstr.d_namlen = len;

	//
	// Fake inode
	//
	dirp->dirstr.d_ino = dummy++;

	//
	// Now set up for the next call to readdir
	//

	dirp->curr += len + 1;
	if (dirp->curr >= (dirp->start + dirp->size)) {
	    dirp->curr = NULL;
	}

	return &(dirp->dirstr);

    } else
	return NULL;
}

//
// Telldir returns the current string pointer position
//

long
telldir(DIR *dirp)
{
	return (long) dirp->curr;	/* ouch! pointer to long cast */
}

//
// Seekdir moves the string pointer to a previously saved position
// (Saved by telldir).

void
seekdir(DIR *dirp, long loc)
{
	dirp->curr = (char *) loc;	/* ouch! long to pointer cast */
}

//
// Rewinddir resets the string pointer to the start
//

void
rewinddir(DIR *dirp)
{
	dirp->curr = dirp->start;
}

//
// This just free\'s the memory allocated by opendir
//

void
closedir(DIR *dirp)
{
	free(dirp->start);
	free(dirp);
}
