/*
 *   This file defines everything we need to handle
 *   nestable bindable macros.
 */
#include "def.h"
/*
 *   Currently we allow a maximum of 40 keys to be
 *   bound to macros.
 */
#define MAXKMAC (40)
struct macrobind {
   KEY key, *macro ;
} mbind[MAXKMAC] ;
extern KEY *kbdmip, *kbdmop ;
extern KEY *kbdnext ;
extern KEY *lmalloc() ;
/*
 *   This macro takes the currently defined keyboard
 *   macro and binds it to a key.  It copies the
 *   macro higher in the array, and points things at
 *   that copy for the next one.
 */
bindmacrotokey(f, n, c) {
   register struct macrobind *mp ;
   KEY *cur ;
   KEY *p, *q ;
   KEY bc ;
   SYMBOL *sp ;

   if (kbdmip) {
      ewprintf("Not now") ;
      return(FALSE) ;
   }
   sp = symlookup("call-last-kbd-macro") ;
   if (sp==NULL) {
      ewprintf("Couldn't find call-last-kbd-macro") ;
      return(FALSE) ;
   }
   cur = (KEY *)lmalloc(sizeof(KEY) * (long)(kbdnext-kbdm)) ;
   if (cur==NULL) {
      ewprintf("Out of macro space") ;
      return(FALSE) ;
   }
   if (kbdmop==NULL)
      ewprintf("Set key to macro: ") ;
   bc = (int) getkey(0) ;
   for (p=kbdm, q=cur; p<kbdnext;)
      *q++ = *p++ ;
   for (mp=mbind; mp<mbind+MAXKMAC; mp++) {
      if (mp->key==bc) {
         free(mp->macro) ;
         mp->macro = cur ;
      } else if (mp->key==0) {
         mp->key = bc ;
         mp->macro = cur ;
         binding[(KEY) bc] = sp ;
         return(TRUE) ;
      }
   }
   ewprintf("Out of macro space") ;
   return(FALSE) ;
}
/*
 *   Here we find the macro associated with a particular
 *   key, and bind everything.
 */
KEY *kbdloc(k) {
   register struct macrobind *p ;

   if (k==KRANDOM || k==(KCTLX|'E'))
      return(kbdm) ;
   if (k==KMACCUR)
      return(kbdnext + 10) ;
   for (p=mbind; p<mbind+MAXKMAC; p++)
      if (k==p->key)
         return(p->macro) ;
   return(NULL) ;
}
/*
 *   This routine does some initialization which is best
 *   done here.
 */
kbdminit() {
   kbdm[0] =(KCTLX|')') ;
   kbdnext = kbdm + 1 ;
}
/*
 *   We even allow a stack to handle recursive macros.  We
 *   don't let it get very deep, though.
 */
#define KSDEP (5)
KEY *kbdstack[KSDEP] ;
KEY **kbdsp = kbdstack ;
/*
 *   This routine pushes a position onto the stack.
 */
pushkbdm(k)
KEY *k ;
{
   if (kbdsp >= kbdstack + KSDEP)
      return(1) ;
   *kbdsp++ = k ;
   return(0) ;
}
/*
 *   Here we pop one off.
 */
popkbdm() {
   if (kbdsp > kbdstack)
      kbdmop = (*--kbdsp) ;
   else
      kbdmop = NULL ;
}
/*
 *   This forgets all of the macros.
 */
flushkbdm() {
   kbdsp = kbdstack ;
}
