#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/tasks.h>
#include <libraries/dosextens.h>
#include <functions.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif

/*
 * _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' + 1 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.
 */

char *
_GetPathFromLock (lock, buffer, buffer_length)
     BPTR lock;
     char *buffer;
     int buffer_length;
{
  register char *p;
  register BPTR fl, next_fl;
  register int length;
  struct FileInfoBlock *fib;

  /* 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 = NULL;

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

  fl = DupLock (lock);

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

  while (fl != NULL)
    {
      if (Examine (fl, fib) == DOSFALSE)
	{
	  errno = EIO;
	  UnLock (fl);
	  return NULL;
	}
      next_fl = ParentDir (fl);
      UnLock (fl);
      if (p != NULL)
	{
	  if (next_fl != NULL)
	    *--p = '/';
	  else
	    *--p = ':';
	}
      else
	{
	  p = buffer + buffer_length - 1;
	  *p = '\0';
	  if (next_fl == NULL)
	    *--p = ':';
	}
      length = strlen (fib->fib_FileName);
      p -= length;
      if (p <= buffer)
	{
	  if (next_fl != NULL)
	    UnLock (next_fl);
	  return NULL;
	}
      memcpy (p, fib->fib_FileName, length);
      fl = next_fl;
    }

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

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

  return buffer;
}


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

  proc = (struct Process *) FindTask (NULL);

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

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


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

  path = _get_pwd (buffer, MAXPATHLEN);
  if (path == NULL)
    {
      sprintf (buffer, "getwd: %s", strerror (errno));
      return NULL;
    }
  return path;
}


char *
getcwd (buffer, buffer_length)
     char *buffer;
     int buffer_length;
{
  if (buffer == NULL)
    {
      buffer = malloc (buffer_length + 2);
      if (buffer == NULL)
	{
	  errno = ENOMEM;
	  return NULL;
	}
    }
  return _get_pwd (buffer, buffer_length);
}
