/*->c.xmain  */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <stdarg.h>
#include <ctype.h>
#include <time.h>
#include <locale.h>
#include <setjmp.h>




#include "h.os"
#include "h.wimp"
#include "h.sprite"
#include "h.werr"
#include "h.wimpt"
#include "h.bbc"
#include "h.akbd"
#include "h.flex"


#include "h.wos"
#include "h.swinos"
#include "h.swis"
#include "h.trans"

#include "h.xext"
#include "h.xint"




/*****************************************************************************/


char * errmessages[MAXERRNO]=
{
 "{SCR04} '%s' {SCR05} '%s'",
 "{SCR06}",
 "{SCR07}",
 "{SCR08}",
 "{SCR09}",
 "{SCR10}",
 "{SCR11}",
 "{SCR12}",
 "{SCR13} %s",
 "{SCR14}",
 "{SCR15}",
 "{SCR16}",
 "{SCR17}",
 "{SCR18}",
 "{SCR19}",
 "{SCR20}",
 "{SCR21}",
 "{SCR22}",
 "{SCR23}",
 "{SCR01}",
 "{SCR24}"
};


jmp_buf xraisejmp;



void xraise(int errno, ...)
{
 va_list args;
 char v[128];
 char * format;

 format=errmessages[errno];

 va_start(args, errno);
 vsprintf(v, format, args);
 va_end(args);

 trans(v,sizeof(v));

 if(!throwbackstart())
 {
  throwbacksend(Throwback_ReasonProcessing,lexfile);
  throwbacksend(Throwback_ReasonErrorDetails,lexfile,lexline,2,v);

  throwbackend();
 }
 else werr(0,"{SCR25}:%s {SCR26} %d {SCR27} %s\n",v,lexline,lexfile);

 longjmp(xraisejmp,1);
}





/*****************************************************************************/
/* Library functions */


void printi(int fp)
{
 printf("%d",stack[fp]);
}


void prints(int fp)
{
 printf("%s",stringptr(stack[fp]));
}


/* string to int */

int stoi(int fp)
{
 return(atoi(stringptr(stack[fp])));
}


/* int to dec string */

int itos(int fp)
{
 char temp[16];
 sprintf(temp,"%d",stack[fp]);
 return(createstring(temp));
}


/* to hex string */

int itoxs(int fp)
{
 char temp[16];
 sprintf(temp,"%x",stack[fp]);
 return(createstring(temp));
}


/* return char n of string */

int schar(int fp)
{
 return(*(stringptr(stack[fp])+stack[fp+1]));
}


/* make string of char */

int chars(int fp)
{
 int    s;
 char * p;

 s=mkstring(1);
 p=stringptr(s);
 *p++=stack[fp];
 *p=0;

 return(s);
}

/* string len */

int slen(int fp)
{
 return(stringlen(stack[fp]));
}

/*
int mids(int fp)
{
 int    s;
 char * p;
 char * q;
 int    len;

 len=stack[fp+2];

 s=mkstring(len);

 p=stringptr(stack[fp])+stack[fp+1];
 q=stringptr(s);

 memcpy(q,p,len);
 *(q+len)=0;

 return(s);
}
*/




/* string mids(string s,int start,int len) */

int mids(int fp)
{
 int    s;
 char * p;
 char * q;
 int    len;
 int    slen;
 int    start;

 start=stack[fp+1];
 len=stack[fp+2];
 slen=stringlen(stack[fp]); /* C style doesn't count last 0 */

 if(start<0) start=0;
 if(start>slen) start=slen;

 if(len<0) len=0;
 if((len+start)>slen) len=slen-start;

 s=mkstring(len);

 p=stringptr(stack[fp])+start;
 q=stringptr(s);

 memcpy(q,p,len);
 *(q+len)=0;

 return(s);
}





void bbcvdu(int fp)
{
 bbc_vdu(stack[fp]);
}


int bbcinkey(int fp)
{
 return(bbc_inkey(stack[fp]));
}


int bbcadval(int fp)
{
 return(bbc_adval(stack[fp]));
}


int bbcget(int fp)
{
 return(bbc_get());
 fp=0;
}



int getenvs(int fp)
{
 char * p=getenv(stringptr(stack[fp]));

 if(p) 
 {
  assignstring(stack[fp],p);
  return(1);
 }
 else
  return(0);
}



int osclis(int fp)
{
 os_error * ep;

 ep=os_cli(stringptr(stack[fp]));

 if(ep)
 {
  assignstring(stack[fp],ep->errmess);
  return(1);
 }
 else
  return(0);

}


int systems(int fp)
{
 char string[256];
 strcpy(string,stringptr(stack[fp]));
 return(system(string));
}



void ourfx(int fp)
{
 fx(stack[fp],stack[fp+1],stack[fp+2]);
}



/* return r1, use r0,r1,r2 */

int ourswi13(int fp)
{
 os_regset rx;

 rx.r[0]=stack[fp+1];
 rx.r[1]=stack[fp+2];
 rx.r[2]=stack[fp+3];

 os_swix(stack[fp],&rx);

 return(rx.r[1]);
}




int osversion(int fp)
{
 os_regset rx;

 rx.r[0]=129;
 rx.r[1]=0;
 rx.r[2]=0xFF;

 os_swix(OS_Byte,&rx);

 return(rx.r[1]);
}



#define MAXFILE 4

FILE * fpn[MAXFILE];



/* int    fileopen(string & name,string & mode)  // open file  */
/* returns file handle >0
   or 0 if file can't be opened. */


int fileopen(int fp)
{
 int i;

 for(i=0;i<MAXFILE;i++) if(!fpn[i]) break;

 if(i==MAXFILE) zraise(ZFILEMAX);

 fpn[i]=fopen(stringptr(stack[fp]),stringptr(stack[fp+1]));

 if(fpn[i]) return(i+1);
 else       return(0);
}



/* int    fileclose(int handle);                  // close file */
/* return 0 if sucessfuly closed
   or non zero on error. */


int fileclose(int fp)
{
 int i=stack[fp]-1;
 int code; 

 code=1;

 if(i>=0 && i<MAXFILE && fpn[i])
 {
  code=fclose(fpn[i]);
  fpn[i]=0;
 }

 return(code);
}



/* int    filewrites(string & s,int handle);      // write string to file */
/* return non zero on error
   or         0 if OK

   Trailing zero not written.
 */

int filewrites(int fp)
{
 int i=stack[fp+1]-1;

 if(i>=0 && i<MAXFILE && fpn[i])
 {
  return(fputs(stringptr(stack[fp]),fpn[i]));
 }
 return(1);
}




/* int    filewritei(int i,int handle);           // write int    to file */
/* return non zero on error
           0 if OK */


int filewritei(int fp)
{
 int i=stack[fp+1]-1;

 if(i>=0 && i<MAXFILE && fpn[i])
 {
  return(!fwrite(&(stack[fp]),4,1,fpn[i]));
 }
 return(1);
}




/* int    fileerror(int handle);                  // check for error */
/* return non zero if an error has occured
   or  0 if OK */

int fileerror(int fp)
{
 int i=stack[fp]-1;

 if(i>=0 && i<MAXFILE && fpn[i])
 {
  return(ferror(fpn[i]));
 }
 return(1);
}



/* int    fileeof(int handle);                    // check for eof   */
/* return non zero on EOF
   or 0 if not eof */

int fileeof(int fp)
{
 int i=stack[fp]-1;

 if(i>=0 && i<MAXFILE && fpn[i])
 {
  return(feof(fpn[i]));
 }
 return(1);
}



/* int    filereadi(int handle);                  // read int        */
/* return integer read */

int filereadi(int fp)
{
 int i=stack[fp]-1;
 int temp;

 if(i>=0 && i<MAXFILE && fpn[i])
 {
  fread(&temp,4,1,fpn[i]);
  return(temp);
 }
 return(0);
}





/* int    filereads(string & s,int handle);       // read string     */
/* return non zero on error
   or         0 if OK */

#define SBFLEN 128


int filereads(int fp)
{
 int  i=stack[fp+1]-1;
 char temp[SBFLEN];
 int  s=stack[fp];
 int  first;

 if(i>=0 && i<MAXFILE && fpn[i])
 {
  first=1;

  while(1)
  {
   if(fgets(temp,SBFLEN,fpn[i]))
   {
    if(first)
    {
     assignstring(s,temp);
     first=0;
    }
    else
    {
     appendstring(s,temp);
    }
   }

   if(ferror(fpn[i])) return(1);
   if(feof(fpn[i]))
   {
    if(first) return(1);
    else      break;
   }
   if(strlen(temp)<(SBFLEN-1) || temp[SBFLEN-2]=='\n') break;
  }
  return(0);
 }
 return(1);
}







/* int    fileput(int i,int handle);              // put byte to file */
/* return the character written or EOF on error */

int fileputc(int fp)
{
 int i=stack[fp+1]-1;

 if(i>=0 && i<MAXFILE && fpn[i])
 {
  return(fputc(stack[fp],fpn[i]));
 }
 return(EOF);
}




/* int    fileget(int handle);                    // get byte from file */
/* return byte or EOF on error */

int filegetc(int fp)
{
 int i=stack[fp]-1;

 if(i>=0 && i<MAXFILE && fpn[i])
 {
  return(fgetc(fpn[i]));
 }
 return(EOF);
}



/* int    fileseek(int offset,int handle);  */
/* return non zero for an improper request
   or 0 if OK */


int fileseek(int fp)
{
 int i=stack[fp+1]-1;

 if(i>=0 && i<MAXFILE && fpn[i])
 {
  return(fseek(fpn[i],stack[fp],SEEK_SET));
 }
 return(1);
}


/* int    filetell(int handle);  */
/* return -1 on error or the file position >=0 if OK. */

int filetell(int fp)
{
 int i=stack[fp]-1;

 if(i>=0 && i<MAXFILE && fpn[i])
 {
  return((int)ftell(fpn[i]));
 }
 return(-1);
}



void xerrorbox(int fp)
{
 zraise(ZUSER,stringptr(stack[fp]));
}


int xconfirm(int fp)
{
 return(confirm(CONYN,stringptr(stack[fp])));
}


void xexit(int fp)
{
 zraise(ZEXIT);
 fp=0;
}


int xobjectexists(int fp)
{
 return(fexists(stringptr(stack[fp])));
}


void xstartscan(int fp)
{
 fp=0;
 startscan();
}


int xnextobject(int fp)
{
 fxstat f;

 if(nextitem(stringptr(stack[fp]),&f,stringptr(stack[fp+1])))
 {
  assignstring(stack[fp+2],f.name);
  return(f.f.object);
 }
 else
  return(0);
}





typedef struct programstage
{
 int code;
 int stage;
 int nostrings;
} programstage;



programstage * prstack; 
int            prstages;



/* removes the last file */

void xremfile(void)
{
 if(prstages)
 {
  prstages--;

  xcodesize=prstack[prstages].code;
  flex_chunk((flex_ptr)&xcodeheap,xcodesize,XCODECHUNK);

  xremstage(prstack[prstages].stage);

  setstrings(prstack[prstages].nostrings);

  flex_chunk((flex_ptr)&prstack,prstages*sizeof(programstage),PRSTACKCHUNK);
 }
}






/* adds another file to program */
/* return 1 OK 0 ERROR          */

int xaddfile(char * filename,int mode,int exec)
{
 if(lexstart(filename,mode))
 {
  if(!setjmp(xraisejmp))
  {
   flex_chunk((flex_ptr)&prstack,
                        (prstages+1)*sizeof(programstage),PRSTACKCHUNK);

   prstack[prstages].code=xcodesize;
   prstack[prstages].stage=xaddstage();
   prstack[prstages].nostrings=nostrings;
   prstages++;

   xparse();

   lexend(mode);

   if(exec) xexec("main",NULL,NULL,NULL);

   return(1);
  }
  else
  {
   lexend(mode);
   xremfile();
   return(0);
  }
 }
 return(0);
}





void xstart(void)
{
 flex_alloc((flex_ptr)&buff,0);
 flex_alloc((flex_ptr)&prstack,PRSTACKCHUNK);
 prstages=0;

 xsymstart();
 xstringstart();
 xcodestart();
}


