/*
 * Here are all the bits needed to pretend we're a Unix box.
 * Plus some memory handling.
 */


#include <stdlib.h>
#include "swis.h"
#include "local.h"


/* Unix sleep. */

int sleep (time_t delay)
{
  delay *= CLOCKS_PER_SEC;
  delay += clock ();
  while (clock () < delay);
  return (0);
}


/* Unix file system. */

char    _open_mode[][4] = {"rb", "wb", "rb+"};
FILE   *_open_temp;
static  _kernel_osfile_block osfile_block;

int access (const char *file, int mode)
{
  int i;

  if (!_kernel_osfile (5, file, &osfile_block))
      return 0;

  i = ((osfile_block.end & 0040) >> 4) | ((osfile_block.end & 0020) >> 2) |
    ((osfile_block.end & 0002)) | ((osfile_block.end & 0001) << 2);

  if (i & 0002)
    i |= 0001;

  if ((i & mode) != mode)
      return -1;

  return 0;
}


int stat (const char *file, struct stat *buf)
{
  if (!_kernel_osfile (5, file, &osfile_block))
    return -1;

  if ((((unsigned int) osfile_block.start) >> 20) == 0xfff)
    {
      unsigned int t1, t2, tc;

      t1 = (unsigned int) (osfile_block.end);
      t2 = (unsigned int) (osfile_block.start & 0xff);

      tc = 0x6e996a00U;
      if (t1 < tc)
	t2--;
      t1 -= tc;
      t2 -= 0x33;

      t1 = (t1 / 100) + (t2 * 42949673U);
      t1 -= (t2 / 25);

      buf->st_mtime = t1;
    }
  else
    buf->st_mtime = 0;

  return 0;
}


/* Handle dynamic areas */

static _kernel_swi_regs swi_regs_in, swi_regs_out;

void *get_memory_area (int size, char *area_name, int *handle)
{
  int area_base, carry;

  swi_regs_in.r[0] = 0;
  swi_regs_in.r[1] = -1;
  swi_regs_in.r[2] = size;
  swi_regs_in.r[3] = -1;
  swi_regs_in.r[4] = 0x80;
  swi_regs_in.r[5] = size;
  swi_regs_in.r[6] = 0;
  swi_regs_in.r[7] = 0;
  swi_regs_in.r[8] = (int) area_name;

  (void) _kernel_swi_c (OS_DynamicArea | XOS_Bit,
                        &swi_regs_in, &swi_regs_out, &carry);

   if (!(carry & 1))
    return malloc ((unsigned) size);

  *handle     = swi_regs_out.r[1];
  area_base   = swi_regs_out.r[3];

  (void) _kernel_swi (OS_ReadDynamicArea, &swi_regs_in, &swi_regs_out);

  if (swi_regs_out.r[0] < size)
    return NULL;

  return (void *) area_base;
}

void destroy_memory_area (int handle)
{
  if (handle == 0)
    return;

  swi_regs_in.r[0] = 1;
  swi_regs_in.r[1] = handle;

  (void) _kernel_swi (OS_DynamicArea, &swi_regs_in, &swi_regs_out);
}


