#include <swis.h>
#include "baseincs.h"
#include "problem.h"
#include "probman.h"
#include <sys/stat.h>

static const char *id="@(#)$Id: riscos.cpp,v 1.10 1998/12/10 13:00:54 chrisb Exp $";

#define RC5PC 0x523C0
#define RC5PC_Version       RC5PC+0
#define RC5PC_Title         RC5PC+1
#define RC5PC_Status        RC5PC+2
#define RC5PC_On            RC5PC+3
#define RC5PC_Off           RC5PC+4
#define RC5PC_WhatPCCard    RC5PC+5
#define RC5PC_BufferStatus  RC5PC+6
#define RC5PC_AddBlock      RC5PC+7
#define RC5PC_RetriveBlock RC5PC+8

int __root_stack_size = 16384;

bool riscos_in_taskwindow;

struct RC5PCstruct
{
       u8 internal_status;
       u8 result;
       u8 zero;
       u8 zero1;
       u32 timeslice;
       u64 key;
       u64 iv;
       u64 plain;
       u64 cypher;
       u64 keysdone;
       u64 iterations;
       u64 zero2;
};

extern "C"
{

  extern unsigned int read_monotonic_time();
  extern void riscos_upcall_6();

  int riscos_count_cpus(void)
  {
      unsigned int s;
      _kernel_oserror *err=_swix(RC5PC_Status,_OUT(0),&s);
      if (err == NULL)
      {
          if (s & 1)
          {
              return 2;
          }
      }
      return 1;
  }

  char *riscos_x86_determine_name(void)
  {
      static char buf[100];
      char *mfr, *cpu;
      _kernel_oserror *err=_swix(RC5PC_WhatPCCard,_OUTR(2,3),&mfr,&cpu);
      if (err == NULL)
      {
	  sprintf(buf," with %s %s card",mfr,cpu);
	  return buf;
      }
      else
      {
	  return "";
      }
  }

  unsigned int sleep(unsigned int s)
  {
    // This doesn't work - it won't return in a taskwindow when the screen blanks
    // if DPMS is in use.
    //_swix(OS_Byte,_INR(0,2),129,(s*100)&0xff,((s*100)>>8)&0x7f);
    unsigned int t = read_monotonic_time();

    while (read_monotonic_time() - t < s * 100)
      {
        if (riscos_in_taskwindow)
          {
            riscos_upcall_6();
          }
      }

    return 0;
  }

  void usleep (unsigned int us)
  {
    unsigned int t = read_monotonic_time();

    while (read_monotonic_time() - t < us / 10000)
      {
        if (riscos_in_taskwindow)
          {
            riscos_upcall_6();
          }
      }
  }

  int stat (const char *filename, struct stat *buf)
  {
    unsigned int obtype;
    _kernel_oserror *err;
    //    printf("stat: filename = %s\n",filename);
    err = _swix(OS_File, _INR(0,1)|_OUT(0)|_OUT(4),
                         17, riscos_localise_filename(filename), &obtype, &buf->st_size);
    if (err)
      {
	return -1;
      }
    //    printf("stat: obtype = %u\n",obtype);
    if (obtype == 1)
      {
	//	printf("stat: size = %d\n",buf->st_size);
	return 0;
      }
    return -1;
  }

  int fstat(int s, struct stat *buf)
  {
    if (_swix(OS_Args, _INR(0,1)|_OUT(2), 2, s, &buf->st_size))
      return -1;
    else
      return 0;
  }

#if 0
  FILE *my_fopen(const char *filename, const char *mode)
  {
      return fopen(riscos_localise_filename(filename), mode);
  }

  int my_unlink(const char *filename)
  {
      return remove(riscos_localise_filename(filename));
  }
#endif

  int ftruncate(int f, off_t size)
  {
      if (_swix(OS_Args, _INR(0,2), 3, f, size))
          return -1;
      else
          return 0;
  }

  void riscos_clear_screen()
  {
      _swix(OS_WriteI + 12, 0);
  }
  void riscos_backspace()
  {
      _swix(OS_WriteI + 8, 0);
      _swix(OS_WriteI + 32, 0);
      _swix(OS_WriteI + 8, 0);
  }
  static char client_path[1024];

  int riscos_find_local_directory(const char *progname)
  {
      _kernel_oserror *e;
      char *dot;

#if 1
      e = _swix(OS_FSControl, _INR(0,5), 37, progname, client_path,
      	    	    	    "Run$Path", 0, sizeof client_path - 1);
#else
      e = _swix(OS_FSControl, _INR(0,5), 37, "@", client_path,
      	    	    	    0, 0, sizeof client_path - 1);
#endif
      if (e == NULL && (dot = strrchr(client_path, '.')) != NULL)
        {
      	  dot[1] = '\0';
	  return 0;
        }
      else
        {
	  return -1;
        }
  }

  char *riscos_localise_filename(const char *filename)
  {
      static char buffer[1024];

      if (_swix(OS_FSControl, _INR(0,5), 37, filename, buffer,
                              0, client_path, sizeof buffer))
        {
          strcpy(buffer, filename);
        }

      //printf("Localised to \"%s\"\n", buffer);

      return buffer;
  }

  bool riscos_check_taskwindow()
  {
      int in_taskwindow;

      if (_swix(TaskWindow_TaskInfo, _IN(0)|_OUT(0), 0, &in_taskwindow))
        {
          return false;
        }

      if (in_taskwindow)
        {
          return true;
        }
      else
        {
          return false;
        }
  }
}

