/* riscos - low level interface  */
/*
      G.C.Wraith  26/1/94

*/
#include <string.h>
#include "bob.h"

#define IN_BUFSIZE 256
#define LOWEST_CHAR 32
#define HIGHEST_CHAR 255
#define VARNAMESIZE 64

extern int ishexdigit(char);
#ifdef RISCOS
extern int Readline(int buf,int bufsize,int lowest,int highest);
extern int Sysvar(char * name,char * buffer,int bufsize);
extern void SwiSet(int swino,int *reg);
extern int *Time(void);
extern int Chain0(char *cmd);
extern int StartTask0(char *cmd);
extern int Taskwin_query(void);

extern int Align(int);

extern int bob_rand(void);   /* hack to avoid clash of stdlib with bob.h */
extern void bob_srand(int);  /* hack to avoid clash of stdlib with bob.h */
extern void bob_exit(int);   /* hack to avoid clash of stdlib with bob.h */

int w_task;

static char in_buf[IN_BUFSIZE];
static char var_buf[IN_BUFSIZE];
static char varname[VARNAMESIZE];

void w_closedown(void)
{
 int r[8];
 r[0] = w_task;
 r[1] = 0x4b534154;
 SwiSet(0x400dd,r);
 w_task = 0;
}

int w_report(char *s)
{
 int r[8];
 var_buf[0] = ' ';
 strcpy(in_buf,"Bob");
 strcpy(&var_buf[4],s);
 r[0] = (int) var_buf;
 r[1] = 19;
 r[2] = (int) in_buf;
 SwiSet(0x400df,r);
 return (r[1]);
}

/* ------------ built in functions ----------------*/
/* input using OS_ReadLine */
int xinput(int argc)
{
 int len;
 argcount(argc,0);
 len = Readline((int) in_buf,IN_BUFSIZE,LOWEST_CHAR,HIGHEST_CHAR);
 set_string(sp,makestring(in_buf));
 return (0);
}

/* Get value of system variable using OS_ReadVarVal */
int xsysvar(int argc)
{
 char *p;
 int type;
 argcount(argc,1);
 chktype(0,DT_STRING);
 p = getcstring(varname,VARNAMESIZE,sp);
 type = Sysvar(p,var_buf,IN_BUFSIZE);
 if (!type)
   set_string(&sp[1],makestring(var_buf));
 else
   set_nil(&sp[1]);
 sp++;
 return(0);
}

/* Get time in centiseconds using OS_Word */
int xtime(int argc)
{
 int *t;
 argcount(argc,0);
 t = Time();
 set_integer(sp,*t);
 return (0);
}

/* use hack for stdlib */
int xrand(int argc)
{
 argcount(argc,0);
 set_integer(sp,bob_rand());
 return(0);
}

/* use hack for stdlib */
int xsrand(int argc)
{
 argcount(argc,1);
 chktype(0,DT_INTEGER);
 bob_srand(sp->v.v_integer);
 ++sp;
 set_nil(sp);
 return(0);
}

/* use stdlib hack */
int xquit(int argc)
{
 char *s;
 argcount(argc,1);
 chktype(0,DT_STRING);
 s = getcstring(in_buf,IN_BUFSIZE,sp);
 /* replace osputs by wimp procedure ? */
 osputs(s);
 if (w_task) w_closedown();
 bob_exit(0);
 return(0);
}

/* call a SWI with register values in a vector */
int xswi(int argc)
{
 int r[8];
 int i;
 VALUE *regv;
 STRING *s;
 int swino, len;
 argcount(argc,2);
 switch ((&sp[1])->v_type)
   {
     case DT_INTEGER:
        swino = (&sp[1])->v.v_integer;
        break;
     case DT_STRING:
        s = straddr(&sp[1]);
        if ((len = s->str_size) >= IN_BUFSIZE)
            error0("String too long\n");
        strncpy(in_buf,s->str_data,len);
        in_buf[len] = '\0';
        r[1] = (int) in_buf;
        SwiSet(57,r);
        swino = r[0];
        break;
     default:
        error0("Bad type for SWI name\n");
        break;
    }
 chktype(0,DT_VECTOR);
 if (vecgetsize(sp)<8)
    error0("Vector needs 8 components\n");
 for(i=0;i<8;i++)
   {
    regv = vecgetelement(sp,i);
    switch(regv->v_type)
     {
      case DT_INTEGER:
         r[i] = regv->v.v_integer;
         break;
      case DT_STRING:
         r[i] = (int) strgetdata(regv);
         break;
      case DT_NIL:
         r[i] = 0;
         break;
      default:
        error1d("Component %d not an integer or string\n",i);
        break;
      }
   }
 SwiSet(swino,r);
 for(i=0;i<8;i++)
   set_integer(vecgetelement(sp,i),r[i]);
 sp[2] = *sp;
 sp += 2;
 return(0);
}

#endif
/* get numerical value from string */
int xval(int argc)
{
 int x,i, sign, len;
 float y, d;
 char *s;
 x = i = 0;
 sign = 1;
 argcount(argc,1);
 chktype(0,DT_STRING);
 len = strgetsize(sp);
 s = strgetdata(sp);
 while (s[i] == ' ' && i < len) ++i;
 switch (s[i])
 {
  case '&':
     i++;
     while (i < len && ishexdigit(s[i]))
       x = (x<<4)+((s[i]<'a')?(s[i++]-'0'):(s[i++]-'W'));
     break;
  case '-':
    sign = -1;
  case '+':
    ++i;
  default:
    while (i<len && isdigit(s[i]))
      x = 10*x + s[i++] - '0';
 }
 if (s[i++] == '.')
 {
  d = 0.1;
  y = x;
  while (i<len && isdigit(s[i]))
    {
     y += (s[i++] - '0')*d;
     d /= 10.0;
    }
  set_real(&sp[1],sign*y);
 }
 else
   set_integer(&sp[1],sign*x);
 ++sp;
 return(0);
}

/* get address of string */
int xstring_addr(int argc)
{
 argcount(argc,1);
 chktype(0,DT_STRING);
 set_integer(&sp[1],(int) strgetdata(sp));
 sp++;
 return(0);
}

/* peek a string from an address */
int xpeeks(int argc)
{
 char *t;
 char *s;
 int len;
 STRING *val;
 len = 0;
 argcount(argc,1);
 chktype(0,DT_INTEGER);
 s = t = (char *) sp->v.v_integer;
 while (*(t++) >= ' ') len++;
 val = newstring(len);
 strncpy(val->str_data,s,len);
 set_string(&sp[1],val);
 sp++;
 return(0);
}

/* peek a word from an address */
int xpeekw(int argc)
{
 int *n;
 argcount(argc,1);
 chktype(0,DT_INTEGER);
 n = (int *) sp->v.v_integer;
 set_integer(&sp[1],*n);
 sp++;
 return(0);
}

/* peek a byte from an address */
int xpeekb(int argc)
{
 char *n;
 argcount(argc,1);
 chktype(0,DT_INTEGER);
 n = (char *) sp->v.v_integer;
 set_integer(&sp[1],*n);
 sp++;
 return(0);
}

/* poke a string to an address */
int xpokes(int argc)
{
 STRING *s;
 char *ptr;
 argcount(argc,2);
 chktype(0,DT_STRING);
 chktype(1,DT_INTEGER);
 s = straddr(sp);
 ptr = (char *) (&sp[1])->v.v_integer;
 strncpy(ptr,s->str_data,s->str_size);
 sp[2] = *sp;
 sp += 2;
 return(0);
}

/* poke a word to an address */
int xpokew(int argc)
{
 int *n;
 argcount(argc,2);
 chktype(0,DT_INTEGER);
 chktype(1,DT_INTEGER);
 n = (int *) (&sp[1])->v.v_integer;
 *n = sp->v.v_integer;
 sp[2] = *sp;
 sp +=2;
 return(0);
}

/* poke a byte to an address */
int xpokeb(int argc)
{
 char *n;
 argcount(argc,2);
 chktype(0,DT_INTEGER);
 chktype(1,DT_INTEGER);
 n = (char *) (&sp[1])->v.v_integer;
 *n = sp->v.v_integer;
 sp[2] = *sp;
 sp +=2;
 return(0);
}

#ifdef RISCOS
/* wimp_closedown */
int xwimp_closedown(int argc)
{
 argcount(argc,0);
 if (w_task) w_closedown();
 set_nil(sp);
 return(0);
}

/* put a message in a box */
int xwimp_report(int argc)
{
 argcount(argc,1);
 chktype(0,DT_STRING);
 set_integer(&sp[1],w_report(strgetdata(sp)));
 sp++;
 return(0);
}

/* wimp_init */
int xwimp_init(int argc)
{
 int r[8];
 argcount(argc,3);
 chktype(2,DT_INTEGER);
 chktype(1,DT_STRING);
 r[0] = (&sp[2])->v.v_integer;
 r[1] = 0x4b534154;
 r[2] = (int) strgetdata(&sp[1]);
 switch(sp->v_type)
  {
   case DT_INTEGER:
     r[3] = sp->v.v_integer;
     break;
   case DT_STRING:
     r[3] = (int) strgetdata(sp);
     break;
   default:
     error0("String or integer required for message list\n");
     break;
   }
  SwiSet(0x400c0,r);
  if (r[0] < 300)
    error0("RISC OS 3 needed");
  set_integer(&sp[3],w_task = r[1]);
  sp += 3;
  return(0);
}

int xstart_task(int argc)
{
 char cmd[256];
 argcount(argc,1);
 chktype(0,DT_STRING);
 getcstring(cmd,256,sp);
 set_integer(&sp[1],(Taskwin_query())?StartTask0(cmd):Chain0(cmd));
 sp++;
 return(0);
}

/* call(code,r0) - call code at code, passing integer r0  */
int xcall(int argc)
{
 argcount(argc,2);
 chktype(0,DT_INTEGER);
 chktype(1,DT_INTEGER);
 (*sp[1].v.v_code)(sp->v.v_integer);
 sp += 2;
 return(0);
}
#endif
