/*->c.key */

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

#include "h.os"
#include "h.wimp"
#include "h.bbc"
#include "h.flex"
#include "h.swis"

#include "h.def"
#include "h.wos"
#include "h.main"
#include "h.mym"
#include "h.pr"

#include "h.script"

#include "h.key"






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


static char * uncode(char * string,int byte)
{
 if(byte>127)
 {
  *string++='|';
  *string++='!';
  byte&=0x7F;
 }

 if(byte<32 && byte>=0)
 {
  *string++='|';
  *string++=byte+'@';
 }
 else
 if(byte=='|')
 {
  *string++='|';
  *string++='|';
 }
 else
 if(byte=='\"')
 {
  *string++='|';
  *string++='\"';
 }
 else
 if(byte=='<')
 {
  *string++='|';
  *string++='<';
 }
 else
 if(byte==127)
 {
  *string++='|';
  *string++='?';
 }
 else
 if(byte=='{')
 {
  *string++='|';
  *string++='{';
 }
 else
 if(byte>0)
 {
  *string++=byte;
 }

 *string=0;

 return(string);
}




static int    cmaxlen;
static int    clen;
static char * cres;


static int consub(int byte)
{
 *cres++=byte;
 clen++;
 return(clen>=cmaxlen);
}



int convert(char * string,char * result,int * len,int maxlen)
{
 int code;

 cmaxlen=maxlen;
 clen=0;
 cres=result;

 code=expandmacro(consub,string);

 *len=clen;

 return(code);
}


static int codechar(char * string)
{
 char       buffer[20];
 int        len;
 if(strlen(string)==0) return(-1);
 convert(string,buffer,&len,20);
 if(len==1) return(buffer[0]);
 else       return(-1);
}


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


static char toktab[58][4]=
{
 'a','c','k',    6,
 'a','p','c',    159,
 'b','e','l',    7,
 'b','s', 0 ,    8,
 'c','a','n',    24,
 'c','c','h',    148,
 'c','r' ,0 ,    13,
 'c','s','i',    155,
 'd','c','1',    17,
 'd','c','2',    18,
 'd','c','3',    19,
 'd','c','4',    20,
 'd','c','s',    144,
 'd','l','e',    16,
 'e','m', 0 ,    25,
 'e','n','q',    5,
 'e','o','t',    4,
 'e','p','a',    151,
 'e','s','a',    135,
 'e','s','c',    27,
 'e','t','b',    23,
 'e','t','x',    3,
 'f','f', 0 ,    12,
 'f','s', 0 ,    28,
 'g','s', 0 ,    29,
 'h','t', 0 ,    9,
 'h','t','j',    137,
 'h','t','s',    136,
 'i','n','d',    132,
 'l','f', 0 ,    10,
 'm','w', 0 ,    149,
 'n','a','k',    21,
 'n','e','l',    133,
 'n','u','l',    0,
 'o','s','c',    157,
 'p','l','d',    139,
 'p','l','u',    140,
 'p','m', 0 ,    158,
 'p','u','1',    145,
 'p','u','2',    146,
 'r','i', 0 ,    141,
 'r','s', 0 ,    30,
 's','i', 0 ,    15,
 's','o', 0 ,    14,
 's','o','h',    1,
 's','p', 0 ,    32,
 's','p','a',    150,
 's','s','2',    142,
 's','s','3',    143,
 's','s','a',    134,
 's','t', 0 ,    156,
 's','t','s',    147,
 's','t','x',    2,
 's','u','b',    26,
 's','y','n',    22,
 'u','s', 0 ,    31,
 'v','t', 0 ,    11,
 'v','t','s',    138
};



static int tokcmp(const void * p,const void * q)
{
 int f;
 int s;
 int n=3;
 char * p1=(char*)p;
 char * q1=(char*)q;

 while(n--)
 {
  f=toupper(*p1++);
  s=toupper(*q1++);
  if(f!=s) return(f-s);
 }

 return(0);
}



static int findtoken(char * string)
{
 char * p;

 if(strlen(string)<4)
 {
  p=bsearch(string,toktab,sizeof(toktab)/4,4,tokcmp);
  if(p) return(*(p+3));
 }

 return(-1);
}






static int sysmacro(expandfn exfn,char * string)
{
 os_regset rx;
 os_error * ep;
 char      buff[128];
 int       i;

 if(isdigit(*string) || *string=='&')
 {
  rx.r[0]=10;
  rx.r[1]=(int)string;
  rx.r[2]=(1<<31);

  ep=os_swix(OS_ReadUnsigned,&rx); /* PRM 585 */
  if(!ep) exfn(rx.r[2]);
 }
 else
 {
  rx.r[0]=(int)string;
  rx.r[1]=(int)buff;
  rx.r[2]=128;
  rx.r[3]=0;
  rx.r[4]=3;

  ep=os_swix(OS_ReadVarVal,&rx); /* PRM 750 */

  if(!ep) for(i=0;i<rx.r[2];i++) exfn(buff[i]);
 }
 return(0);
}



/* internal macro, can be keycode, 'keycode, token, or stuff */


static int intmacro(expandfn exfn,char * string)
{
 int c;

 if((c=findtoken(string))>=0) exfn(c);

 return(0);
}




#define BAR0 0
#define BAR1 1
#define BAR2 2
#define BAR3 3


#define MAC0 0
#define MAC1 1
#define MAC2 2


int expandmacro(expandfn exfn,char * string)
{
 int  i;
 int  ch;
 int  barstate;
 int  mstate;
 char buff[128];
 int  m;
 int  curlys;

 curlys=0;
 m=0;
 barstate=BAR0;
 mstate=MAC0;

 for(i=0;i<strlen(string);i++)
 {
  ch=string[i];

  switch(barstate)
  {
   case BAR0:                  /* the state looking for | seqs */
             if(ch=='|') 
             {
              barstate=BAR1;
              continue;
             }
             break;


   case BAR2:                  /* must be a | */
             if(ch!='|') 
             {
              ch+=128;
             }
             else
             {
              barstate=BAR3;
              continue;
             }
             break;

   case BAR3:
   case BAR1:                  /* | something */

             switch(ch)
             {
              case '!':
                       barstate=BAR2;
                       continue;

              case '?':
                       ch=127;
                       break;


               default:
                       if(ch>='@' && ch<='_') ch=ch-'@';
                       break;
             }
             if(barstate==BAR3) ch+=128;
             break;
  }

  /* now got a code 0..255 */

  switch(mstate)
  {
   case MAC0:
             if(ch=='<' && !barstate)
             {
              mstate=MAC1;
              m=0;
             }
             else
             if(ch=='{' && !barstate)
             {
              mstate=MAC2;
              curlys=0;
              m=0;
             }
             else
             if(exfn(ch)) return(1);
             break;

   case MAC1:        /* a <something> seq, accumulate then expand */
             if(ch=='>')
             {
              buff[m]=0;
              sysmacro(exfn,buff);
              mstate=MAC0;
             }
             else
              buff[m++]=ch;
             break;

   case MAC2:        /* a {something} seq, accumulate then expand */
             if(ch=='}' && !curlys && !barstate)
             {
              buff[m]=0;
              intmacro(exfn,buff);
              mstate=MAC0;
             }
             else
             {
              buff[m++]=ch;
              if(!barstate)
              {
               if(ch=='}') curlys--;
               else
               if(ch=='{') curlys++;
              }
             }
             break;

  }
  barstate=0;
 }

 if(mstate)
  for(i=0;i<m;i++) if(exfn(buff[i])) return(1);

 return(0);
}

