/*->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.def"
#include "h.wos"
#include "h.main"
#include "h.mym"
#include "h.swis"
#include "h.swinos"
#include "h.pr"

#include "h.script"

#include "h.vtdef"

#include "h.vxdef"
#include "h.vxsend"

#include "h.key"



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

#define KEYNONE -1

#define MNKEYS 96


typedef struct
{
 char       name[8];
 short int  code[6];
} ktype;



static ktype ktable[MNKEYS]=
{  
   /* name */   /* N         S         C        A        CS       AS     */

   "Escape"       ,0x1b     ,0x1b     ,0x1b    ,0x1b    ,0x1b    ,0x1b    ,
   "f1"           ,0x181    ,0x191    ,0x1a1   ,0xda1   ,0x1b1   ,0x15b1  ,
   "f2"           ,0x182    ,0x192    ,0x1a2   ,0xda2   ,0x1b2   ,0x15b2  ,
   "f3"           ,0x183    ,0x193    ,0x1a3   ,0xda3   ,0x1b3   ,0x15b3  ,
   "f4"           ,0x184    ,0x194    ,0x1a4   ,0xda4   ,0x1b4   ,0x15b4  ,
   "f5"           ,0x185    ,0x195    ,0x1a5   ,0xda5   ,0x1b5   ,0x15b5  ,
   "f6"           ,0x186    ,0x196    ,0x1a6   ,0xda6   ,0x1b6   ,0x15b6  ,
   "f7"           ,0x187    ,0x197    ,0x1a7   ,0xda7   ,0x1b7   ,0x15b7  ,
   "f8"           ,0x188    ,0x198    ,0x1a8   ,0xda8   ,0x1b8   ,0x15b8  ,
   "f9"           ,0x189    ,0x199    ,0x1a9   ,0xda9   ,0x1b9   ,0x15b9  ,
   "f10"          ,0x1ca    ,0x1da    ,0x1ea   ,0xdea   ,0x1fa   ,0x15fa  ,
   "f11"          ,0x1cb    ,0x1db    ,0x1eb   ,0xdeb   ,0x1fb   ,0x15fb  ,
   "f12"          ,0x1cc    ,0x1dc    ,0x1ec   ,0xdec   ,0x1fc   ,0x15fc  ,
   "Print"        ,0x180    ,0x190    ,0x1a0   ,0xda0   ,0x1b0   ,0x15b0  ,
   "SLock"        ,0x1a0e   ,0xa0e    ,0x60e   ,0xe0e   ,0x120e  ,0x160e  ,
   "Break"        ,0x1a1b   ,0xa1b    ,0x61b   ,0xe1b   ,0x121b  ,0x161b  ,
   "`"            ,0x60     ,0x7e     ,0x60    ,0x60    ,0x107e  ,0x147e  ,

#ifdef NEVER
   "!"            ,0x31     ,0x21     ,0x431   ,0xc31   ,0x1021  ,0x1421  ,
   "@"            ,0x32     ,0x40     ,0x0     ,0xcc2   ,0x10c3  ,0x14c4  ,
   "#"            ,0x33     ,0x23     ,0x433   ,0xc33   ,0x1023  ,0x1423  ,
   "$"            ,0x34     ,0x24     ,0x434   ,0xc34   ,0x1024  ,0x1424  ,
   "%"            ,0x35     ,0x25     ,0x435   ,0xc35   ,0x1025  ,0x1425  ,
   "^"            ,0x36     ,0x5e     ,0x41e   ,0xc1e   ,0x101e  ,0x141e  ,
   "&"            ,0x37     ,0x26     ,0x437   ,0xc37   ,0x1026  ,0x1426  ,
   "*"            ,0x38     ,0x2a     ,0x438   ,0xc38   ,0x102a  ,0x142a  ,
   "("            ,0x39     ,0x28     ,0x439   ,0xc39   ,0x1028  ,0x1428  ,
   ")"            ,0x30     ,0x29     ,0x430   ,0xc30   ,0x1029  ,0x1429  ,  
#endif

   "1"            ,0x31     ,0x21     ,0x431   ,0xc31   ,0x1021  ,0x1421  ,
   "2"            ,0x32     ,0x40     ,0x0     ,0xcc2   ,0x10c3  ,0x14c4  ,
   "3"            ,0x33     ,0x23     ,0x433   ,0xc33   ,0x1023  ,0x1423  ,
   "4"            ,0x34     ,0x24     ,0x434   ,0xc34   ,0x1024  ,0x1424  ,
   "5"            ,0x35     ,0x25     ,0x435   ,0xc35   ,0x1025  ,0x1425  ,
   "6"            ,0x36     ,0x5e     ,0x41e   ,0xc1e   ,0x101e  ,0x141e  ,
   "7"            ,0x37     ,0x26     ,0x437   ,0xc37   ,0x1026  ,0x1426  ,
   "8"            ,0x38     ,0x2a     ,0x438   ,0xc38   ,0x102a  ,0x142a  ,
   "9"            ,0x39     ,0x28     ,0x439   ,0xc39   ,0x1028  ,0x1428  ,
   "0"            ,0x30     ,0x29     ,0x430   ,0xc30   ,0x1029  ,0x1429  ,  


   "-"            ,0x2d     ,0x5f     ,0x1f    ,0xc1f   ,0x101f  ,0x141f  ,
   "="            ,0x3d     ,0x2b     ,0x43d   ,0xc3d   ,0x102b  ,0x142b  ,
   ""            ,0xa3     ,0xa4     ,0x1a3   ,0x1a3   ,0x1a4   ,0x1a4   ,
   "BS"           ,0x1a08   ,0xa08    ,0x608   ,0xe08   ,0x1208  ,0x1608  ,
   "Insert"       ,0x1cd    ,0x1dd    ,0x1ed   ,0xded   ,0x1fd   ,0x15fd  ,  
   "Home"         ,0x1a1e   ,0xa1e    ,0x61e   ,0xe1e   ,0x121e  ,0x161e  ,  
   "PageUp"       ,0x1b9f   ,0xb8f    ,0x7bf   ,0xfbf   ,0x13af  ,0x17af  ,
   "NLock"        ,0x1a22   ,0xa22    ,0x622   ,0xe22   ,0x1222  ,0x1622  ,
   "K/"           ,0x1a2f   ,0xa2f    ,0x62f   ,0xe2f   ,0x122f  ,0x162f  ,
   "K*"           ,0x1a2a   ,0xa2a    ,0x62a   ,0xe2a   ,0x122a  ,0x162a  ,
   "K#"           ,0x1a23   ,0xa23    ,0x623   ,0xe23   ,0x1223  ,0x1623  ,
   "Tab"          ,0x18a    ,0x19a    ,0x1aa   ,0xdaa   ,0x1ba   ,0x15ba  ,
   "Q"            ,0x71     ,0x51     ,0x11    ,0xc11   ,0x1011  ,0x1411  ,
   "W"            ,0x77     ,0x57     ,0x17    ,0xc17   ,0x1017  ,0x1417  ,
   "E"            ,0x65     ,0x45     ,0x5     ,0xc05   ,0x1005  ,0x1405  ,
   "R"            ,0x72     ,0x52     ,0x12    ,0xc12   ,0x1012  ,0x1412  ,
   "T"            ,0x74     ,0x54     ,0x14    ,0xc14   ,0x1014  ,0x1414  ,
   "Y"            ,0x79     ,0x59     ,0x19    ,0xc19   ,0x1019  ,0x1419  ,
   "U"            ,0x75     ,0x55     ,0x15    ,0xc15   ,0x1015  ,0x1415  ,
   "I"            ,0x69     ,0x49     ,0x9     ,0xc09   ,0x1009  ,0x1409  ,
   "O"            ,0x6f     ,0x4f     ,0xf     ,0xc0f   ,0x100f  ,0x140f  ,
   "P"            ,0x70     ,0x50     ,0x10    ,0xc10   ,0x1010  ,0x1410  ,
   "["            ,0x5b     ,0x7b     ,0x1b    ,0xc1b   ,0x101b  ,0x141b  , 
   "]"            ,0x5d     ,0x7d     ,0x1d    ,0xc1d   ,0x101d  ,0x141d  ,
   "\\"           ,0x5c     ,0x7c     ,0x1c    ,0xc1c   ,0x101c  ,0x141c  , 
   "Delete"       ,0x7f     ,0x87f    ,0x47f   ,0xc7f   ,0x107f  ,0x147f  ,
   "Copy"         ,0x18b    ,0x19b    ,0x1ab   ,0xdab   ,0x1bb   ,0x15bb  ,
   "PageDwn"      ,0x1b9e   ,0xb8e    ,0x7be   ,0xfbe   ,0x13ae  ,0x17ae  ,
   "K7"           ,0x1a37   ,0xa37    ,0x637   ,0xe37   ,0x1237  ,0x1637  ,
   "K8"           ,0x1a38   ,0xa38    ,0x638   ,0xe38   ,0x1238  ,0x1638  ,
   "K9"           ,0x1a39   ,0xa39    ,0x639   ,0xe39   ,0x1239  ,0x1639  ,
   "K-"           ,0x1a2d   ,0xa2d    ,0x62d   ,0xe2d   ,0x122d  ,0x162d  ,
   "A"            ,0x61     ,0x41     ,0x1     ,0xc01   ,0x1001  ,0x1401  ,
   "S"            ,0x73     ,0x53     ,0x13    ,0xc13   ,0x1013  ,0x1413  ,
   "D"            ,0x64     ,0x44     ,0x4     ,0xc04   ,0x1004  ,0x1404  ,
   "F"            ,0x66     ,0x46     ,0x6     ,0xc06   ,0x1006  ,0x1406  ,
   "G"            ,0x67     ,0x47     ,0x7     ,0xc07   ,0x1007  ,0x1407  ,  
   "H"            ,0x68     ,0x48     ,0x8     ,0xc08   ,0x1008  ,0x1408  ,
   "J"            ,0x6a     ,0x4a     ,0xa     ,0xc0a   ,0x100a  ,0x140a  ,
   "K"            ,0x6b     ,0x4b     ,0xb     ,0xc0b   ,0x100b  ,0x140b  ,
   "L"            ,0x6c     ,0x4c     ,0xc     ,0xc0c   ,0x100c  ,0x140c  , 
   ":"            ,0x3b     ,0x3a     ,0x43b   ,0xc3b   ,0x103a  ,0x143a  ,

#ifdef NEVER
   "\""           ,0x27     ,0x22     ,0x427   ,0xc27   ,0x1022  ,0x1422  ,
#endif

   "'"            ,0x27     ,0x22     ,0x427   ,0xc27   ,0x1022  ,0x1422  ,

   "Return"       ,0xd      ,0x80d    ,0x40d   ,0xc0d   ,0x100d  ,0x140d  ,
   "K4"           ,0x1a34   ,0xa34    ,0x634   ,0xe34   ,0x1234  ,0x1634  ,
   "K5"           ,0x1a35   ,0xa35    ,0x635   ,0xe35   ,0x1235  ,0x1635  ,
   "K6"           ,0x1a36   ,0xa36    ,0x636   ,0xe36   ,0x1236  ,0x1636  ,
   "K+"           ,0x1a2b   ,0xa2b    ,0x62b   ,0xe2b   ,0x122b  ,0x162b  ,
   "Z"            ,0x7a     ,0x5a     ,0x1a    ,0xc1a   ,0x101a  ,0x141a  ,
   "X"            ,0x78     ,0x58     ,0x18    ,0xc18   ,0x1018  ,0x1418  ,
   "C"            ,0x63     ,0x43     ,0x3     ,0xc03   ,0x1003  ,0x1403  ,
   "V"            ,0x76     ,0x56     ,0x16    ,0xc16   ,0x1016  ,0x1416  ,
   "B"            ,0x62     ,0x42     ,0x2     ,0xc02   ,0x1002  ,0x1402  ,        "N"            ,0x6e     ,0x4e     ,0xe     ,0xc0e   ,0x100e  ,0x140e  ,
   "M"            ,0x6d     ,0x4d     ,0xd     ,0xc0d   ,0x100d  ,0x140d  ,
   ","            ,0x2c     ,0x3c     ,0x42c   ,0xc2c   ,0x103c  ,0x143c  ,
   "."            ,0x2e     ,0x3e     ,0x42e   ,0xc2e   ,0x103e  ,0x143e  ,
   "/"            ,0x2f     ,0x3f     ,0x42f   ,0xc2f   ,0x103f  ,0x143f  ,
   "CUp"          ,0x18f    ,0x19f    ,0x1af   ,0xdaf   ,0x1bf   ,0x15bf  ,
   "K1"           ,0x1a31   ,0xa31    ,0x631   ,0xe31   ,0x1231  ,0x1231  ,
   "K2"           ,0x1a32   ,0xa32    ,0x632   ,0xe32   ,0x1232  ,0x1632  ,
   "K3"           ,0x1a33   ,0xa33    ,0x633   ,0xe33   ,0x1233  ,0x1633  ,
   "Space"        ,0x20     ,0x20     ,0x20    ,0x20    ,0x20    ,0x20    ,
   "CLeft"        ,0x18c    ,0x19c    ,0x1ac   ,0xdac   ,0x1bc   ,0x15bc  ,
   "CDown"        ,0x18e    ,0x19e    ,0x1ae   ,0xdae   ,0x1be   ,0x15be  ,
   "CRight"       ,0x18d    ,0x19d    ,0x1ad   ,0xdad   ,0x1bd   ,0x15bd  ,
   "K0"           ,0x1a30   ,0xa30    ,0x630   ,0xe30   ,0x1230  ,0x1630  ,
   "K."           ,0x1a2e   ,0xa2e    ,0x62e   ,0xe2e   ,0x122e  ,0x162e  ,
   "Enter"        ,0x1a0d   ,0xa0d    ,0x60d   ,0xe0d   ,0x120d  ,0x160d
};


static char * keyprefix[6]={"","S_","C_","A_","CS_","AS_"};




typedef struct
{
 char * name;
 ktype  kpatch;
} kpatchstr;




#define MAXPATCH3 2

static kpatchstr kpatch3[MAXPATCH3]=
{
  "9", "9"      ,0x39     ,0x28     ,0x409   ,0xc09   ,0x1009  ,0x1409  ,
  "0", "0"      ,0x30     ,0x29     ,0x4c0   ,0xcc2   ,0x10c3  ,0x14c4  
};


#define MAXPATCH35 12

static kpatchstr kpatch35[MAXPATCH35]=
{
 "1",  "1"     ,0x31     ,0x21     ,0x401   ,0xc01   ,0x1001  ,0x1401  ,
 "2",  "2"     ,0x32     ,0x22     ,0x402   ,0xc02   ,0x1002  ,0x1402  ,
 "3",  "3"     ,0x33     ,0xa3     ,0x403   ,0xc03   ,0x1003  ,0x1403  ,
 "4",  "4"     ,0x34     ,0x24     ,0x404   ,0xc04   ,0x1004  ,0x1404  ,
 "5",  "5"     ,0x35     ,0x25     ,0x405   ,0xc05   ,0x1005  ,0x1405  ,
 "6",  "6"     ,0x36     ,0x5e     ,0x41e   ,0xc1e   ,0x141e  ,0x141e  ,
 "7",  "7"     ,0x37     ,0x26     ,0x407   ,0xc07   ,0x1007  ,0x1406  ,
 "8",  "8"     ,0x38     ,0x2a     ,0x408   ,0xc08   ,0x1008  ,0x1408  ,
 "9",  "9"     ,0x39     ,0x28     ,0x409   ,0xc09   ,0x1009  ,0x1409  ,
 "0",  "0"     ,0x30     ,0x29     ,0x4c0   ,0xcc2   ,0x10c3  ,0x14c4  ,  
 "",  "#"     ,0x23     ,0x7e     ,-1      ,-1      ,-1      ,-1      ,
 "`",  "`"     ,0x60     ,0xac     ,0x60    ,0x60    ,-1      ,-1      ,
};



void os3keypatch(void)
{
 int     patch;
 char  * target;
 int     maxpatch;
 kpatchstr * kpatch;
 int    i;

 if(os3 || os35)
 {
  if(os35)                      /* notice os3 always true */
  {
   os_cli("Hearsay_Patch35");
   maxpatch=MAXPATCH35;
   kpatch=kpatch35;
  }
  else
  {
   maxpatch=MAXPATCH3;
   kpatch=kpatch3;
  }

  for(patch=0;patch<maxpatch;patch++)
  {
   target=kpatch[patch].name;
  
   for(i=0;i<MNKEYS;i++)
   {
    if(!strcmp(target,ktable[i].name))
    {
     ktable[i]=kpatch[patch].kpatch;
     break;
    }
   }
  }
 }
}




/* returns either key type for string, or -1 for not a key string */

int keytype(char * string)
{
 int i;
 int prefix=0;
 int hit=0;

 for(prefix=5;prefix>0;prefix--)
 {
  i=0;
  while(1)
  {
   if(string[i]!=keyprefix[prefix][i]) break;
   i++;
   if(!keyprefix[prefix][i])
   {
    hit=1;
    string+=i;
    break;
   }
  }
  if(hit) break;
 }


 for(i=0;i<MNKEYS;i++)
 {
  if(!cstrcmp(ktable[i].name,string)) return(ktable[i].code[prefix]);
 }

 return(KEYNONE);
}



/* return string form for string */

char * keystring(int code)
{
 static char name[8];
 int    i;
 int    j;

 for(i=0;i<MNKEYS;i++)
 {
  for(j=0;j<6;j++)
  {
   if(ktable[i].code[j]==code)
   {
    strcpy(name,keyprefix[j]);
    strcat(name,ktable[i].name);
    return(name);
   }
  }
 }

 name[0]=0;
 return(name);
}


/*****************************************************************************/
/* chunk of code for handling keyboard escape sequences */

#define CESC    0x1C0
#define SESC    0x1C1
#define AESC    0x1C2
#define CSESC   0x1C3
#define ASESC   0x1C4
#define NESC    0x1C5
#define SACESC  0x1C6
#define ACESC   0x1C7

#define XCESC   0x1D0
#define XSESC   0x1D1
#define XAESC   0x1D2
#define XCSESC  0x1D3
#define XASESC  0x1D4
#define XNESC   0x1D5
#define XSACESC 0x1D6
#define XACESC  0x1D7



static int keyescflag;

int keyexpand(int * key,int * pass)
{
 int ch=*key;


 if(keyescflag)
 {
  *key=ch+keyescflag;
  keyescflag=0;
  *pass=0;
  return(1);
 }
 else
 if(ch>=CESC && ch<=ACESC)
 {
  keyescflag=((ch-CESC+1)<<10);
  *key=-1;
  return(0);
 }
 else
 if(ch>=XCESC && ch<=XACESC)
 {
  keyescflag=((ch-XCESC+1)<<10)+0x200;
  *key=-1;
  return(0);
 }

 return(1);
}



void keytrash(void)
{


}



static int keyboardon=0;
static int repeatrate;
static int brkeffect;

void keyboard_on(int autorepeat)
{
 os_regset rx;

 if(!keyboardon)  /* if keyboard not active, then stash auto rate */
 {
  rx.r[0]=196;
  rx.r[1]=0;
  rx.r[2]=255;

  os_swix(OS_Byte,&rx);

  repeatrate=rx.r[1];

  rx.r[0]=247;
  rx.r[1]=0;
  rx.r[2]=255;

  os_swix(OS_Byte,&rx);

  brkeffect=rx.r[1];
 }

 if(autorepeat) autorepeat=repeatrate;
 fx(196,autorepeat,0);

 fx(247,0x55,0);   /* was 0x45 */     /* make break effect %01010101 */


 fx(202,0,255-4-2);     /* put num lock on / scroll lock off */
 fx(118,0,0);           /* reflect in LED's */

 rx.r[0]=1;

 os_swix(Hearsay_Keyboard,&rx);

 keyboardon=1;
 keytrash();
}


void keyboard_off(void)
{
 os_regset rx;

 if(keyboardon)
 {
  fx(196,repeatrate,0);
  fx(247,brkeffect,0);
  keyboardon=0;
 }

 rx.r[0]=0;

 os_swix(Hearsay_Keyboard,&rx);

 keytrash();
}



/* changes keyboard state, but depending on if we have caret anyway */

void keyboardoncaret(int set)
{
 findcaret();
 if(chandle==whandle[TEK] || chandle==whandle[VDATA] ||
    chandle==whandle[VTERM]) 
 {
  if(set)
  {
   if(chandle==whandle[TEK] || chandle==whandle[VTERM]) keyboard_on(automode);
   else
   if(chandle==whandle[VDATA]) keyboard_on(vxauto);
  }
  else    keyboard_off();
 }
}


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

static keyhandler mkeyfn;

/* typical string output function */
/* return 1 on failure            */

int keyoutput(int ch)
{
 mkeyfn(&ch);
 return(0);
}



/* passed a key press, and a function to pass keypresses to */
/* look up key number in macro table                        */
/* if present expand definition, and pass on                */
/* else just pass the key on                                */

void keymacro(keyhandler keyfn,int * key)
{
 int  ch=*key;
 int  nm;
 int  mr;

 mr=macrorecorder(ch);
 nm=findmacro(NULL,ch);

 if(nm!=-1 && nm!=mr)
 {
  mkeyfn=keyfn;
  expandamacro(keyoutput,nm);
  *key=-1;
 }
 else
  keyfn(key);
}

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


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;


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);
}


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);
}


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


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
};



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);
}



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);
}






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 */


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

 if((c=findtoken(string))>=0) exfn(c);
 else
 if(*string=='\'')
 {                   /* better be key macro */
  if((c=keytype(string+1))>=0) exfn(c);
 }
 else
 {             /* maybe key macro, or macro, or else stuff */
  if((c=keytype(string))>=0)
  {
   d=findmacro(NULL,c);
   if(d>=0) expandamacro(exfn,d);/*expandamacro(keyoutput,d);*/
   else     exfn(c);
  }
  else
  if((c=findmacro(string,0))>=0)
  {
   return(expandamacro(exfn,c));
  }
  else
  if(!cstrcmp(string,"mbx"))
  {
   return(expandmacro(exfn,mbxno));
  }
  else
  {    /* stuff */
   return(!xexecstuff(string));
  }
 }

 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);
}





int expandamacro(expandfn exfn,int n)
{
 int  code;
 char string[256];

 if(macros[n].flags & MACINUSE) return(1);
 macros[n].flags|=MACINUSE;
 strcpy(string,macros[n].defn+mstrings);
 code=expandmacro(exfn,string);
 macros[n].flags&=~MACINUSE;
 return(code);
}



