/*
 *  This file is part of ixemul.library for the Amiga.
 *  Copyright (C) 1991, 1992  Ray Burr
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* Written and Copyright by Ray Burr. 
 * Put under the GNU Library General Public License.
 * Thanks Ray !
 */

#define KERNEL
#include "ixemul.h"

extern int _dos20;

#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif

#define BASE_EXT_DECL
#define BASE_PAR_DECL	
#define BASE_PAR_DECL0	
#define BASE_NAME	ix.ix_dos_base

__inline static LONG NameFromLock(BASE_PAR_DECL BPTR lock, UBYTE* buffer, long int len)
{
	BASE_EXT_DECL
	register LONG res __asm("d0");
	register void *a6 __asm ("a6");
	register BPTR d1 __asm("d1");
	register UBYTE* d2 __asm("d2");
	register long int d3 __asm("d3");

	a6 = BASE_NAME;
	d1 = lock;
	d2 = buffer;
	d3 = len;
	__asm volatile ("
	jsr a6@(-0x192)"
	: "=r" (res)
	: "r" (a6), "r" (d1), "r" (d2), "r" (d3)
	: "d0", "d1", "a0", "a1", "d2", "d3");
	return res;
}
__inline static BOOL GetCurrentDirName(BASE_PAR_DECL UBYTE* buf, long int len)
{
	BASE_EXT_DECL
	register BOOL res __asm("d0");
	register void *a6 __asm ("a6");
	register UBYTE* d1 __asm("d1");
	register long int d2 __asm("d2");

	a6 = BASE_NAME;
	d1 = buf;
	d2 = len;
	__asm volatile ("
	jsr a6@(-0x234)"
	: "=r" (res)
	: "r" (a6), "r" (d1), "r" (d2)
	: "d0", "d1", "a0", "a1", "d2");
	return res;
}

/* _GetPathFromLock - Given a pointer to an AmigaDOS Lock structure, build
   a rooted path string in a buffer of a given size.  The buffer should be
   at least 'buffer_length' bytes.  Returns a pointer to the result
   or NULL on an error.  'errno' will be set in the case of an error.  This
   function returns the path string based at 'buffer[0]' but it can alter
   any part of the buffer.  */

static char *
_GetPathFromLock (BPTR lock, char *buffer, int buffer_length)
{
  char *p;
  BPTR fl, next_fl;
  int length;
  struct FileInfoBlock *fib;
  int omask;
  char *result = 0;

  /* Allocate space on stack for fib. */

  BYTE fib_Block[sizeof (struct FileInfoBlock) + 2];

  /* Make sure fib is longword aligned. */

  fib = (struct FileInfoBlock *) fib_Block;
  if (((ULONG) fib & 0x02) != 0)
    fib = (struct FileInfoBlock *) ((ULONG) fib + 2);

  p = 0L;

  /* Duplicate the lock so that the directory structure can't change
     while we're doing this. */

  omask = syscall (SYS_sigsetmask, ~0);
  fl = DupLock (lock);

  /* Follow the chain of directories and build the name in 'buffer' */

  while (fl != 0L)
    {
      if (Examine (fl, fib) == DOSFALSE)
	{
	  errno = __ioerr_to_errno(IoErr());
	  UnLock (fl);
	  goto ret;
	}
      next_fl = ParentDir (fl);
      UnLock (fl);
      if (p != 0L)
	{
	  if (next_fl != 0L)
	    *--p = '/';
	  else
	    *--p = ':';
	}
      else
	{
	  p = buffer + buffer_length - 1;	/* fix 20-jan-92 ## mw */
	  *p = '\0';
	  if (next_fl == 0L)
	    *--p = ':';
	}
      length = strlen (fib->fib_FileName);
      p -= length;
      if (p <= buffer)
	{
	  if (next_fl != 0L)
	    UnLock (next_fl);
	  goto ret;
	}
      bcopy (fib->fib_FileName, p, length);
      fl = next_fl;
    }

  /* Move the pathname so that it starts at buffer[0]. */

  bcopy (p, buffer, strlen (p) + 1);

  result = buffer;

ret:
  syscall (SYS_sigsetmask, omask);
  return result;
}


static char *
_get_pwd (char *buffer, int buffer_length)
{
  struct Process *proc;

  proc = (struct Process *) FindTask (0L);

  /* Just return an empty string if this is not a process. */

  if (proc == 0L || proc->pr_Task.tc_Node.ln_Type != NT_PROCESS)
    {
      buffer[0] = '\0';
      return buffer;
    }

  if (_dos20)
    {
      if (GetCurrentDirName (buffer, buffer_length) ||
          NameFromLock (proc->pr_CurrentDir, buffer, buffer_length))
        {
          errno = 0;
          return buffer;
        }
      /* and as the last chance resort to the 1.3 algorithm */
    }

  return _GetPathFromLock (proc->pr_CurrentDir, buffer, buffer_length);
}


char *
getwd (char *buffer)
{
  char *path;

  path = _get_pwd (buffer, MAXPATHLEN);
  if (path == 0L)
    {
      strcpy (buffer, "getwd - ");
      strcat (buffer, strerror (errno));
      return 0L;
    }

  return path;
}


char *
getcwd (char *buffer, int buffer_length)
{

  if (buffer == 0L)
    {
      buffer = syscall (SYS_malloc, buffer_length + 2);
      if (buffer == 0L)
	{
	  errno = ENOMEM;
	  return 0L;
	}
    }

  return _get_pwd (buffer, buffer_length);
}
