/****************************************************************************
 *
 * $Source: /cvsroot/riscossmbserver/smbserver/src/unix/c/getcwd,v $
 * $Date: 2000/04/02 17:00:31 $
 * $Revision: 1.4 $
 * $State: Exp $
 * $Author: david $
 *
 * $Log: getcwd,v $
 * Revision 1.4  2000/04/02 17:00:31  david
 * Changes to allow this to be compiled as a RISCOS module. Mainly
 * fix problems with stack depth which is limited in SVC mode.
 *
 * Revision 1.3  1999/11/23 22:05:11  david
 * Increased filename length to MAXPATHLEN
 * uname and dirent - support for spaces in a filename which
 * is translated to 0xa0 on RISCOS and mapping of obscure DOS
 * filename characters to RICOS characters as 2-327 or the PRMs
 *
 * Revision 1.2  1999/11/07 15:17:20  david
 * dirent: added stuff to support appendFiletype
 * getcwd: addet getFs and variations on getcwd
 *
 * Revision 1.1  1999/05/16 12:00:09  david
 * Initial revision
 *
 * Revision 1.3  1996/10/30 21:59:01  unixlib
 * Massive changes made by Nick Burret and Peter Burwood.
 *
 * Revision 1.2  1996/05/06 09:01:35  unixlib
 * Updates to sources made by Nick Burrett, Peter Burwood and Simon Callan.
 * Saved for 3.7a release.
 *
 * Revision 1.1  1996/04/19 21:35:27  simon
 * Initial revision
 *
 * Completely re-written by Alun Jones, auj@aber.ac.uk, 23/2/94,
 * The original version corrupted the P.S.D. when run.
 *
 * OS_Args 7 and Prefix$Dir hacke by Simon Callan
 * thanks to Andy (torq@gnu.ai.mit.edu) for the OS calls.
 ***************************************************************************/

static const char rcs_id[] = "$Id: getcwd,v 1.4 2000/04/02 17:00:31 david Exp $";

#if 0

#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/os.h>
#include <sys/param.h>
#include <sys/syslib.h>
#include <sys/swis.h>
#else

#include "includes.h"
#include "swis.h"
#include "my_os.h"

/*#define os_file my_os_file
#define os_fclose my_os_fclose
#define os_args my_os_args
#define os_swi my_os_swi*/

/*
#define _POSIX_PATH_MAX 256
#define MAXPATHLEN      _POSIX_PATH_MAX
*/

#define ERANGE  34

#endif

char ro_path[MAXPATHLEN];
char b[MAXPATHLEN];

char *getcwd (char *buffer, size_t size)
{
#if 0
  char ro_path[MAXPATHLEN]; 
#endif
  char var[30];			/* Added by Steffan Corley,
				   is there a known limit on the length of this variable? */
  char *rp = ro_path + MAXPATHLEN - 1;  
#if 0
  char b[MAXPATHLEN];  
#endif
  register char *s, *t;
  int r[10];
  _kernel_oserror *e;
  int handle;

  if (size == 0 && buffer)
    {
      errno = EINVAL;
      return 0;
    }

  /* Try to read CSD variable - added by Steffan Corley for !Virtual
     compatibility */

  r[0] = (int) "FileSwitch$CurrentFilingSystem";
  r[1] = (int) ro_path;
  r[2] = MAXPATHLEN - 1;
  r[3] = 0;
  r[4] = 0;
  myos_swi (OS_ReadVarVal, r);

  if (r[2] > 0)
    {
      ro_path[r[2]] = '\0';
      strcpy (var, "FileSwitch$");
      strcat (var, ro_path);
      strcat (var, "$CSD");
      strcat (ro_path, ":");

      r[0] = (int) var;
      r[1] = (int) (ro_path + (handle = strlen (ro_path)));
      r[2] = MAXPATHLEN - 1 - handle;
      r[3] = 0;
      r[4] = 0;
      myos_swi (OS_ReadVarVal, r);

      if (r[2] > 0)
	{			/* Read CSD var worked, parse the path name */
	  ro_path[r[2] + handle] = '\0';
	  s = ro_path;
	  t = buffer;
	  *t++ = '/';
	  size--;
	  while (*s && *s != '$' && size-- > 0)
	    *t++ = *s++;

	  while (*s && size-- > 0)
	    {
	      if (*s != '.')
		*t++ = *s;
	      else
		*t++ = '/';
	      s++;
	    }
	  if (size == 0)
	    {
	      errno = ERANGE;
	      return 0;
	    }
	  else
	    {
	      *t = '\0';
	      return buffer;
	    }
	}
    }

  /* Try OS_Args 7 (get cannonicalised name) */

  /* Open CSD for read only */
  if (!myos_fopen (0x40, "@", &handle))
    {
      r[0] = 7;
      r[1] = handle;
      r[2] = (int) ro_path;
      r[5] = MAXPATHLEN;
      e = myos_swi (OS_Args, r);
      myos_fclose (handle);
      if (!e)
	{			/* OS_ARGS 7 worked, parse the path name */
	  s = ro_path;
	  t = buffer;
	  *t++ = '/';
	  size--;
	  while (*s && *s != '$' && size-- > 0)
	    *t++ = *s++;

	  while (*s && size-- > 0)
	    {
	      if (*s != '.')
		*t++ = *s;
	      else
		*t++ = '/';
	      s++;
	    }
	  if (size == 0)
	    {
	      errno = ERANGE;
	      return 0;
	    }
	  else
	    {
	      *t = '\0';
	      return buffer;
	    }
	}
    }

  r[0] = (int) "Prefix$Dir";
  r[1] = (int) ro_path;
  r[2] = MAXPATHLEN - 1;
  r[3] = 0;
  r[4] = 0;
  myos_swi (OS_ReadVarVal, r);
  if (r[2] > 0)
    {
      ro_path[r[2]] = '\0';
      s = ro_path;
      t = buffer;
      *t++ = '/';
      size--;
      while (*s && *s != '$' && size-- > 0)
	*t++ = *s++;

      while (*s && size-- > 0)
	{
	  if (*s != '.')
	    *t++ = *s;
	  else
	    *t++ = '/';
	  s++;
	}
      if (size == 0)
	{
	  errno = ERANGE;
	  return 0;
	}
      else
	{
	  *t = '\0';
	  return buffer;
	}
    }
  /* Search backwards up the tree.
   */
  *rp = 0;
  while (1)
    {
      /* Read current directory name
       */
      r[0] = 6;
      r[2] = (int) b;
      if (e = myos_swi (OS_GBPB, r))
	{
	  /* Failed to read dirname
	   * So swap CSD & PSD then chdir back to original
	   * directory.
	   */
	  /*__seterr (e);*/
	  if (*rp)
	    {
	      r[0] = 0;
	      r[1] = (int) "\\";
	      if (!myos_swi (OS_FSControl, r))
		{
		  /* cd \ successful, so now need to cd \.{rp}
		   */
		  *--rp = '.';
		  *--rp = '\\';
		}
	      r[0] = 0;
	      r[1] = (int) rp;
	      myos_swi (OS_FSControl, r);
	    }
	  return 0;
	}

      /* If at root directory then break
       */
      if ((b[2] == '$') && (b[1] == 1))
	{
	  break;
	}

      /* Copy the directory name into the RISC OS name
       * buffer.
       */
      rp -= b[1];
      memcpy (rp, b + 2, b[1]);
      *--rp = '.';

      /* Now select PSD.
       */
      r[0] = 0;
      r[1] = (int) "\\";
      if (myos_swi (OS_FSControl, r))
	{
	  /* If cd \ failed then just cd ^
	   */
	  r[0] = 0;
	  r[1] = (int) "^";
	  myos_swi (OS_FSControl, r);
	}
      else
	{
	  /* Select new PSD.^
	   * This ensures that the PSD doesn't get corrupted by
	   * calling getcwd()
	   */
	  r[0] = 0;
	  r[1] = (int) "\\.^";
	  myos_swi (OS_FSControl, r);
	}
    }

  /* OK, reached the root directory.
   */
  *--rp = '$';

  /* Again, PSD then original directory
   */
  r[0] = 0;
  r[1] = (int) "\\";
  if (e = myos_swi (OS_FSControl, r))
    {
      /*__seterr (e); */
      return 0;
    }

  r[0] = 0;
  r[1] = (int) rp;
  if (e = myos_swi (OS_FSControl, r))
    {
      /* __seterr (e);*/
      return 0;
    }

  /* OK, rp now contains the current directory, and
   * the PSD is unchanged.
   *
   * Next find the FS name.
   */

  /* FS number
   */
  if (e = myos_args (0, 0, 0, r))
    {
      /*__seterr (e);*/
      return 0;
    }

  /* Convert number to name
   */
  r[1] = r[0];
  r[2] = (int) b + 1;
  r[3] = MAXPATHLEN;
  r[0] = 33;
  if (e = myos_swi (OS_FSControl, r))
    {
      /*__seterr (e); */
      return (0);
    }

  /* Now have "/ADFS::", for example in b.
   */
  b[0] = '/';
  strcat (b, "::");

  /* Copy the disk name across to v
   */
  if (strlen (b) < size)
    {
      strcpy (buffer, b);
    }
  else
    {
      errno = ERANGE;
      return 0;
    }

  /* Next find the disk name
   */
  r[0] = 5;
  r[2] = (int) b;
  if (e = myos_swi (OS_GBPB, r))
    {
      /*__seterr (e);*/
      return 0;
    }
  *(b + b[0] + 1) = '\0';
  strcat (b, ".$");
  if (strlen (buffer) + strlen (b + 1) < size)
    {
      strcat (buffer, b + 1);
    }
  else
    {
      errno = ERANGE;
      return 0;
    }

  /* buffer now contains "/ADFS::fred.$", for example.

   * Finally convert the RISC OS name from rp, appending it to v.
   */
  s = buffer + strlen (buffer);
  for (t = rp + 1; *t; t++)
    {
      if (s - buffer == size)
	{
	  errno = ERANGE;
	  return 0;
	}
      *s++ = (*t == '.') ? '/' : *t;
    }
  *s = '\0';
  return buffer;
}

/* BSD version of getcwd.  */

char *
getwd (char *buffer)
{
  return getcwd (buffer, 256);
}

char *getcwd2 (char *buffer, size_t size)
{
#if 0
  char ro_path[MAXPATHLEN];
#endif
  char var[30];			/* Added by Steffan Corley,
				   is there a known limit on the length of this variable? */
  char *rp = ro_path + MAXPATHLEN - 1;
#if 0
  char b[MAXPATHLEN];
#endif
  register char *s, *t;
  int r[10];
  _kernel_oserror *e;
  int handle;

 /* OK, rp now contains the current directory, and
   * the PSD is unchanged.
   *
   * Next find the FS name.
   */

  /* FS number
   */
  if (e = myos_args (0, 0, 0, r))
    {
      /*__seterr (e);*/
      return 0;
    }

  /* Convert number to name
   */
  r[1] = r[0];
  r[2] = (int) b ;
  r[3] = MAXPATHLEN;
  r[0] = 33;
  if (e = myos_swi (OS_FSControl, r))
    {
      /*__seterr (e); */
      return (0);
    }

  /* Now have "ADFS::", for example in b.
   */
  strcat (b, "::");

  /* Copy the disk name across to v
   */
  if (strlen (b) < size)
    {
      strcpy (buffer, b);
    }
  else
    {
      errno = ERANGE;
      return 0;
    }

  /* Next find the disk name
   */
  r[0] = 5;
  r[2] = (int) b;
  if (e = myos_swi (OS_GBPB, r))
    {
      /*__seterr (e);*/
      return 0;
    }
  *(b + b[0] + 1) = '\0';
  strcat (b, ".$");
  if (strlen (buffer) + strlen (b + 1) < size)
    {
      strcat (buffer, b + 1);
    }
  else
    {
      errno = ERANGE;
      return 0;
    }
 
     /* Read current directory name
       */
      r[0] = 6;
      r[2] = (int) b;
      if (e = myos_swi (OS_GBPB, r))
      {
         return 0;
      }                

  *(b + b[0] + 1) = '\0';
 
  if (strlen (buffer) + strlen (b + 1) < size)
    {
      strcat (buffer, b + 1);
    }
  else
    {
      errno = ERANGE;
      return 0;
    }
           

  return buffer;
}


char *getcwd3 (char *buffer, char *buffer2, size_t size, size_t size2)
{
#if 0
  char ro_path[MAXPATHLEN]; 
#endif
  char var[30];			/* Added by Steffan Corley,
				   is there a known limit on the length of this variable? */
  char *rp = ro_path + MAXPATHLEN - 1;
#if 0
  char b[MAXPATHLEN];  
#endif
  register char *s, *t;
  int r[10];
  _kernel_oserror *e;
  int handle;

 /* OK, rp now contains the current directory, and
   * the PSD is unchanged.
   *
   * Next find the FS name.
   */

  /* FS number
   */
  if (e = myos_args (0, 0, 0, r))
    {
      /*__seterr (e);*/
      return 0;
    }

  /* Convert number to name
   */
  r[1] = r[0];
  r[2] = (int) b ;
  r[3] = MAXPATHLEN;
  r[0] = 33;
  if (e = myos_swi (OS_FSControl, r))
    {
      /*__seterr (e); */
      return (0);
    }

  if (strlen (b) < size2)
    {
      strcpy (buffer2, b);
    }
  else
    {
      errno = ERANGE;
      return 0;
    }

  /* Now have "ADFS::", for example in b.
   */
  /*strcat (b, "::"); */

  /* Copy the disk name across to v
   */                   
/*
  if (strlen (b) < size)
    {
      strcpy (buffer, b);
    }
  else
    {
      errno = ERANGE;
      return 0;
    }
*/

  /* Next find the disk name
   */
  r[0] = 5;
  r[2] = (int) b;
  if (e = myos_swi (OS_GBPB, r))
    {
      /*__seterr (e);*/
      return 0;
    }
  *(b + b[0] + 1) = '\0';
  strcat (b, ".$");
  if (strlen (buffer) + strlen (b + 1) < size)
    {
      strcpy (buffer, b + 1);
    }
  else
    {
      errno = ERANGE;
      return 0;
    }
 
     /* Read current directory name
       */
      r[0] = 6;
      r[2] = (int) b;
      if (e = myos_swi (OS_GBPB, r))
      {
         return 0;
      }                

  *(b + b[0] + 1) = '\0';
 
  if (strlen (buffer) + strlen (b + 1) < size)
    {
      strcat (buffer, b + 1);
    }
  else
    {
      errno = ERANGE;
      return 0;
    }
           

  return buffer;
}

char *getFs(char *buffer, size_t size)
{
#if 0
  char ro_path[MAXPATHLEN];  
#endif
  char var[30];			/* Added by Steffan Corley,
				   is there a known limit on the length of this variable? */
  char *rp = ro_path + MAXPATHLEN - 1;
#if 0
  char b[MAXPATHLEN];
#endif
  register char *s, *t;
  int r[10];
  _kernel_oserror *e;
  int handle;

 /* OK, rp now contains the current directory, and
   * the PSD is unchanged.
   *
   * Next find the FS name.
   */

  /* FS number
   */
  if (e = myos_args (0, 0, 0, r))
    {
      /*__seterr (e);*/
      return 0;
    }

  /* Convert number to name
   */
  r[1] = r[0];
  r[2] = (int) b ;
  r[3] = MAXPATHLEN;
  r[0] = 33;
  if (e = myos_swi (OS_FSControl, r))
    {
      /*__seterr (e); */
      return (0);
    }

  if (strlen (b) < size)
    {
      strcpy (buffer, b);
    }
  else
    {
      errno = ERANGE;
      return 0;
    }
}    


