#include <sys/dir.h>
#include <libraries/dosextens.h>
#include <stat.h>

char *convert(char *);

/* I want to change the original sources as little as possible, so I decided
 * that all my functions should work with Amiga filenames. Most of the code
 * I copied from someone else, I only changed opendir()
 *					Cthulu
 */

/*
 * BSD/Unix expansion library for Amiga.
 *
 * closedir() -- system independent directory code
 */

void
closedir(my_dir)
   DIR *my_dir;
{
	UnLock(my_dir->d_lock);
	FreeMem(my_dir, sizeof(DIR));
}


/*
 * BSD/Unix expansion library for Amiga.
 *
 * readdir() -- system independent directory code
 */


struct direct *
readdir(my_dir)
   DIR *my_dir;
{
	static struct direct	result ;

	if (!ExNext(my_dir->d_lock, &(my_dir->d_info)))
		return NULL ;

	result.d_reclen = result.d_ino = 1;	/* Not NULL! */
	(void) strcpy(result.d_name, my_dir -> d_info.fib_FileName);
	result.d_namlen = strlen(result.d_name);
	return &result ;
}

/*
 * BSD/Unix expansion library for Amiga.
 *
 * rewinddir() -- system independent directory code
 */


void
rewinddir(my_dir)
   DIR *my_dir;
{
	if (!Examine(my_dir->d_lock, &(my_dir->d_info)))
		setmem((char *) my_dir, sizeof(DIR), 0) ;
}

/*
 * BSD/Unix expansion library for Amiga.
 *
 * seekdir() -- system independent directory code
 */


/*
 * telldir and seekdir don't work quite right. The problem is that you have
 * to save more than a long's worth of stuff to indicate position, and it's
 * socially unacceptable to alloc stuff that you don't free later under
 * AmigaDOS. So we fake it - you get one level of seek, and dat's all.
 * As of now, these things are untested.
 */

#define DIR_SEEK_RETURN		((long) 1)	/* Not 0! */

void
seekdir(my_dir, where)
   DIR *my_dir;
   long where;
{
	if (where == DIR_SEEK_RETURN)
		my_dir->d_info = my_dir->d_seek ;
	else	/* Makes the next readdir fail */
		setmem((char *) my_dir, sizeof(DIR), 0) ;
}

/*
 * BSD/Unix expansion library for Amiga.
 *
 * telldir() -- system independent directory code
 */


/*
 * telldir and seekdir don't work quite right. The problem is that you have
 * to save more than a long's worth of stuff to indicate position, and it's
 * socially unacceptable to alloc stuff that you don't free later under
 * AmigaDOS. So we fake it - you get one level of seek, and dat's all.
 * As of now, these things are untested.
 */

#define DIR_SEEK_RETURN		((long) 1)	/* Not 0! */
long
telldir(my_dir)
   DIR *my_dir;
{
	my_dir->d_seek = my_dir->d_info ;
	return (long) DIR_SEEK_RETURN ;
}



/*
 * BSD/Unix expansion library for Amiga.
 *
 * opendir() -- system independent directory code
 */


DIR *
opendir(dirname)
   char *dirname;
{
	register DIR	*my_dir, *AllocMem(/* int, int */) ;
	struct FileLock	*Lock(/* char *, int */), *CurrentDir(/* struct FileLock * */) ;

	if ((my_dir = AllocMem(sizeof(DIR), 0)) == NULL)
		return NULL ;

	if (((my_dir->d_lock = Lock(convert(dirname), ACCESS_READ)) == NULL)
		/* If we can't examine it */
		||  !Examine(my_dir->d_lock, &(my_dir->d_info))
		/* Or it's not a directory */
		||  (my_dir->d_info.fib_DirEntryType < 0))
	{
		FreeMem(my_dir, sizeof(DIR)) ;
		return NULL ;
	}
	return my_dir ;
}


/* convert UNIX path-name to AMIGA
 * check_file_name generates a path which ends with .
 * this function changes the original string !!!!
 */
char *convert(char unix_name[])
{
    int lastpos;
    lastpos = strlen(unix_name) -1;
    if(lastpos == 0) /* '.' */
 	unix_name[0] = '\0';   /*  mudlib:  */
    else
	{
	if(unix_name[lastpos] == '.')
	    unix_name[lastpos] = '\0';
	}
    return unix_name;
}


/* remove directory, return -1 if failed.
 * file is an Unix-path !!!
 */
int rmdir(file)
    char *file;
{
    if(!isdir(convert(file)))
	    return -1;
    if(!DeleteFile(file))
	    return -1;   /* does not exist or if directory: not empty */
    else
	    return 0;
}

/* this function was defined in simulate.c too, but I had already written this,
 * so remove the original isdir, and replace it with this code.
 */
int isdir(file)
    char *file;
{
    struct FileInfoBlock *infoBlock;
    int s_isdir;
    struct FileLock	*lock, *Lock(/* char *, int */);

    if(file[0] == '.' && strlen(file) == 1)
	return 1;    /* mudlib: is een directory */

    lock = Lock(file, ACCESS_READ);
    if(lock) {
        infoBlock = (struct FileInfoBlock *) 
                              AllocMem(sizeof(struct FileInfoBlock), 0L);
        if(infoBlock) {
            if( Examine(lock, (BPTR)infoBlock))
		s_isdir = (infoBlock->fib_DirEntryType  < 0) ? 0 : 1;
            FreeMem(infoBlock, sizeof(struct FileInfoBlock));
        }
    UnLock(lock);
    }
    return s_isdir;
}

/* lstat gives different information about a linked file than stat does,
 * but Amiga has no links, so just return stat()
 */
int lstat(char *file, struct stat *data) {
    return stat(file, data);
}
