/*{{{  #includes*/
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <local/bool.h>

#define PUTRC
#include "../h/rcformat.h"

#define PARSER_C

#include "keybind.h"
#include "../h/envvar_str.h"
/*}}}  */

/*{{{  variables*/
private char nullc='\0';
public char *op_def_name = &nullc;
public TOKEN *m_def;
public char *modenames[32];
public int used_modes=0;
public int macro_pos=0;
public int auto_macro=0;
public int ab_macro=0;
public int proin=0;
public int proout=0;
public int knbm_no=0;
public int vm_no=0;
public int cl=0;
public bool mouse=FALSE;
/*}}}  */

/*{{{  name_parse*/
private char *name_parse(char *str,char *er)
{
  if (get_token(FALSE)!=NAME) {
    error_po();
    fprintf(stderr,er);
    return(0);
  }
  strcpy(str,tk_string);

  return(str);
}
/*}}}  */
/*{{{  parse the file*/
public bool process_file(void)
{
  /*{{{  variables*/
  tokens token;
  char   name[name_lg];
  TOKEN  tokenlist[macro_lg];
  TOKEN  *tl_ptr;
  bool   named=FALSE;
  K_SEQ  k;
  /*}}}  */

  rc_put_w((O_RETURN+O_EXE_MACRO+O_QUIT),rc);
  put_mac_count(-1);
  /*{{{  init the keysequence struct*/
  k.count=0;
  /*}}}  */
  /*{{{  handle std-vars*/
  { int i;

    /*{{{  std-vars (tab and screen)*/
    if (!dest_mac) rc_put_c(RC_S_VAR,rc);
    i=creat_var(RD_T_W); if (!dest_mac) rc_put_w(i,rc);
    cl=i=creat_var(CURSOR_LEVEL);if (!dest_mac) rc_put_w(i,rc);
    i=creat_var(SCR_H);  if (!dest_mac) rc_put_w(i,rc);
    i=creat_var(SCR_W);   if (!dest_mac) rc_put_w(i,rc);
    i=creat_var(OCL_ARG_V);   if (!dest_mac) rc_put_w(i,rc);
    /*}}}  */
    /*{{{  mouse_vars*/
    if (m_name[0])
     { if (!dest_mac) rc_put_c(RC_M_VAR,rc);
       i=creat_var(MOUSE_X);if (!dest_mac) rc_put_w(i,rc);
       i=creat_var(MOUSE_Y);if (!dest_mac) rc_put_w(i,rc);
       i=creat_var(MOUSE_B);if (!dest_mac) rc_put_w(i,rc);
       i=creat_var(MOUSE_G);if (!dest_mac) rc_put_w(i,rc);
       i=creat_var(MOUSE_O);if (!dest_mac) rc_put_w(i,rc);
     }
    /*}}}  */
  }
  /*}}}  */
  token=get_token(FALSE);
  do
    /*{{{  one keybind-command*/
    switch (token) {
      case ENDFILE: break;
      case BEGIN: {
        token=get_token(FALSE);
        switch (token) {
          /*{{{  termalias*/
          case TERMALIAS:
           { char replace[name_lg+1];
             tokens tn;

             if (!name_parse(replace,M_T_NAME)) return(TRUE);
             if (!dest_mac) rc_put_c(RC_TERMALIAS,rc);
             if (begin_parse()) return(TRUE);
             while ((tn=get_token(FALSE))!=END)
              { if (tn!=NAME)
                 /*{{{  complain and exit*/
                 { error_po();
                   fprintf(stderr,M_T_NAME);
                   return(TRUE);
                 }
                 /*}}}  */
                /*{{{  print alias to rc*/
                if (!dest_mac)
                 { char *s;

                   rc_put_c(1,rc);
                   s=tk_string;
                   do rc_put_c(*s,rc); while (*s++);
                 }
                /*}}}  */
              }
             /*{{{  print replace to rc*/
             if (!dest_mac)
              { char *s;

                rc_put_c(0,rc);
                s=replace;
                do rc_put_c(*s,rc); while (*s++);
              }
             /*}}}  */
             if (end_parse(M_WANTEND)) return(TRUE);
             break;
           }
          /*}}}  */
          /*{{{  os-extension*/
          case OS_EXT:
             if (begin_parse()) return(TRUE);
             if (verbose) fprintf(stderr,M_ADD_OS_X);
             /*{{{  read all strings*/
             { tokens read;

               if (!dest_mac) rc_put_c(RC_OS_EXTENSION,rc);
               while ((read=get_token(FALSE))==MACRO)
                  if (!dest_mac)
                   { TOKEN *x=tk_macro;

                     if (verbose) fprintf(stderr,tk_string);
                     while (*x) rc_put_c(*x++,rc);
                   }
               if (read!=END)
                { if (read!=ERROR) { error_po();fprintf(stderr,M_WANTEND); }
                  return(0);
                }
               if (!dest_mac) rc_put_c(0,rc);
             }
             /*}}}  */
             if (verbose) fprintf(stderr,M_END_OS_X);
             if (end_parse(M_WANTEND)) return(TRUE);
             break;
          /*}}}  */
          /*{{{  terminal*/
          case TERMINAL:
           { int t_c=0;
             int l;
             K_SEQ k;

             /*{{{  get correct terminals*/
             if ((token=term_name())==NAME)
              /*{{{  only one terminal*/
              strcpy(k.terms[t_c++],tk_string);
              /*}}}  */
             else if (token==BEGIN)
              /*{{{  list of terminals*/
              { while ((token=term_name())!=END)
                   if (token!=NAME)
                    /*{{{  error return*/
                    { error_po();
                      fprintf(stderr,M_T_NAME);
                      return(TRUE);
                    }
                    /*}}}  */
                   else if (t_c==termmax)
                    /*{{{  error return*/
                    { error_po();
                      fprintf(stderr,M_T_MAX);
                      return(TRUE);
                    }
                    /*}}}  */
                   else
                      strcpy(k.terms[t_c++],tk_string);
              }
              /*}}}  */
             else
              /*{{{  error*/
              { error_po();
                fprintf(stderr,M_T_NAME);
                return(TRUE);
              }
              /*}}}  */
             k.count=t_c;
             if (verbose)
                for (l=0;l<t_c;l++) fprintf(stderr,F_T_START,k.terms[l]);
             /*}}}  */
             while ((token=get_token(FALSE))!=END)
                if ((token==BEGIN) && ((token=get_token(FALSE))==KEYALIAS || token==KEYDEF))
                   if (token==KEYDEF)
                    /*{{{  keybind*/
                      t_keydef_code(&k);
                    /*}}}  */
                   else
                    /*{{{  alias*/
                    { char n[name_lg];

                      if (!name_parse(name,M_EXPALIAS)) return(TRUE);
                      if (parse_keysequence(&k)) return(TRUE);
                      for (l=0;l<t_c;l++)
                       { strcpy(n,k.terms[l]);
                         strcat(n,"@");
                         strcat(n,name);
                         creat_alias(n,k.codes[l],k.lg[l]);
                       }
                      if (end_parse(M_ALIEND)) return(TRUE);
                    }
                    /*}}}  */
                else
                 /*{{{  error*/
                 { error_po();
                   fprintf(stderr,M_KBD_BEGIN);
                   return(TRUE);
                 }
                 /*}}}  */
             if (verbose) fprintf(stderr,M_T_END,t_c);
             break;
           }
          /*}}}  */
          /*{{{  alias command*/
          case KEYALIAS: {
            if (!name_parse(name,M_EXPALIAS)) return(TRUE);
            if (parse_keysequence(&k)) return(TRUE);
            creat_alias(name,k.codes[0],k.lg[0]);
            if (end_parse(M_ALIEND)) return(TRUE);
            break;
          }
          /*}}}  */
          /*{{{  user-macros*/
          case DEFMYFIX: {
            if (macro_pos)
             { fprintf(stderr,M_MACGIV);
               error_po();
               return(TRUE);
             }
            if (get_token(FALSE)!=NUMBER)
             { error_po();
               fprintf(stderr,M_NOADDCOUNTER);
             }
            macro_pos=tk_val;
            if (end_parse(M_WANTEND)) return(TRUE);
            break;
          }
          /*}}}  */
          /*{{{  keybind command*/
          case KEYDEF:
             if (keydef_code()) return(TRUE);
             break;
          /*}}}  */
          /*{{{  forward-declaration*/
          case FORWARD: {
            if (!name_parse(name,M_MACNAME)) return(TRUE);
            tokenlist[0]=(TOKEN)((int)O_EXE_MACRO+ ++macro_pos);
            tokenlist[1]=M_END_MACRO;
            if (verbose) fprintf(stderr,F_FOR,macro_pos);
            creat_op(name,FALSE,1,tokenlist,macro_pos,FALSE);
            if (end_parse(M_DEFOEND)) return(TRUE);
            break;
          }
          /*}}}  */
          /*{{{  automacro/abortmacro/promptmacros/knb/view*/
          case VMAC:
          case KNBM:
          case PRO_IN:
          case PRO_OUT:
          case DEFAB:
          case DEFAUTO: {
            int *x=  token==DEFAB?&ab_macro:
                     (token==PRO_IN?&proin:
                     (token==PRO_OUT?&proout:
                     (token==KNBM?&knbm_no:
                     (token==VMAC?&vm_no:
                      &auto_macro))));

            /*{{{  already given?*/
            if (*x) {
              error_po();
              fprintf(stderr,M_DUPAUTO);
              return(TRUE);
            }
            /*}}}  */
            /*{{{  check if macroname given*/
            if (get_token(FALSE)!=OPERATION) {
              error_po();
              fprintf(stderr,M_INVMNAME);
              return(TRUE);
            }
            /*}}}  */
            write_auto_rc(token,*x=tk_operation->place);
            if (end_parse(M_DEFOEND)) return(TRUE);
            break;
          }
          /*}}}  */
          /*{{{  define a new operation*/
          case DEFOP: {
            bool ret_used=FALSE;

            if (!name_parse(name,M_DEFONAME)) return(TRUE);
            /*{{{  prepare M_CALL-information*/
            op_def_name=name;
            m_def=tokenlist;
            /*}}}  */
            if (!(tl_ptr=opt_parse_macro(tokenlist,&ret_used,FALSE))) return(TRUE);
            /*{{{  reset M_CALL-information*/
            op_def_name = &nullc;
            m_def=0;
            /*}}}  */
            creat_op(name,TRUE,tl_ptr-tokenlist,tokenlist,0,ret_used);
            if (end_parse(M_DEFOEND)) return(TRUE);
            break;
          }
          /*}}}  */
          /*{{{  macro commands*/
          case DEFMACRO:
          case INITMACRO: {
            bool def=(bool)(token==DEFMACRO);
            bool dest_found;
            int var_c=int_no;
            readtags tag=(token==DEFMACRO) ? RC_DEFMACRO : RC_INITMACRO;
            int po;
            bool ret_used=FALSE;

            if ((token=get_token(FALSE))==NAME) {
              /*{{{  declaration & definition*/
              po = ++macro_pos;
              strcpy(name,tk_string);
              op_def_name=name;
              m_def=tokenlist;
              /*}}}  */
            } else if (token==OPERATION) {
              /*{{{  definition*/
              if (tk_operation->def) {
                error_po();
                fprintf(stderr,M_DUPDEF);
                return(TRUE);
              }
              strcpy(name,tk_operation->op_name);
              tk_operation->def=TRUE;
              po = (int)*(tk_operation->ops)-(int)O_EXE_MACRO;
              op_def_name=name;
              /*}}}  */
            } else {
              error_po();
              fprintf(stderr,M_INVMNAME);
              return(TRUE);
            }
            dest_found= dest_mac && !(strcmp(dest_mac,name));
            if (!(tl_ptr=opt_parse_macro(tokenlist,&ret_used,def))) return(TRUE);
            if (dest_found && var_c==int_no)
               write_dest_mac(tokenlist,tl_ptr-tokenlist);
            if (write_macro_rc(tag,po,tl_ptr-tokenlist,tokenlist)) return(TRUE);
            if (token!=OPERATION) {
              /*{{{  macro as operation storing*/
              if (def) {
                tokenlist[0]=(TOKEN)((int)O_EXE_MACRO+po);
                creat_op(name,TRUE,1,tokenlist,po,FALSE);
              } else
                creat_op(name,TRUE,tl_ptr-tokenlist,tokenlist,po,ret_used);
              m_def=0;
              op_def_name = &nullc;
              /*}}}  */
            } else if (verbose)
              fprintf(stderr,".\n");
            if (end_parse(M_MDEFNAME)) return(TRUE);
            break;
          }
          /*}}}  */
          /*{{{  multikbd*/
          case MULTIKBD:
             if (mkbd_code()) return(TRUE);
             break;
          /*}}}  */
          /*{{{  mouse*/
          case MOUSEMAP: {
            int i=0;
            TOKEN map[MAX_MOUSE_BUTTONS];

            /*{{{  multiple mouse?*/
            if (mouse) {
              error_po();
              fprintf(stderr,M_MOUSE);
              return(TRUE);
            }
            mouse=TRUE;
            /*}}}  */
            while ((token=get_token(FALSE))!=END)
             /*{{{  handle a button*/
             { if (token==OPCODE)
                /*{{{  opcode*/
                { map[i]=tk_key->num;
                  write_bind(tk_key->name,
                             (char*)(first_mouse_char+i),
                             mouse_kbd);
                }
                /*}}}  */
               else if (token==MACRO && strlen(tk_string)==1)
                /*{{{  simple*/
                { char simple[3];

                  simple[0]='\"';
                  simple[1]=map[i]=tk_string[0];
                  simple[2]='\0';
                  write_bind(simple,
                             (char*)(first_mouse_char+i),
                             mouse_kbd);
                }
                /*}}}  */
               else if (token==OPERATION)
                /*{{{  operation*/
                { if (tk_operation->place==0)
                   /*{{{  error*/
                   { error_po();
                     fprintf(stderr,M_NODEBOUND);
                     return(TRUE);
                   }
                   /*}}}  */
                 map[i]=(TOKEN)((int)O_EXE_MACRO+tk_operation->place);
                 write_bind(tk_operation->op_name,
                            (char*)(first_mouse_char+i),
                            mouse_kbd);
                }
                /*}}}  */
               else
                /*{{{  error*/
                { error_po();
                  fprintf(stderr,M_NOCOMMAND);
                  return(TRUE);
                }
                /*}}}  */
               if (++i==MAX_MOUSE_BUTTONS)
                /*{{{  memory-crash*/
                { error_po();
                  fprintf(stderr,M_NOMEMORY);
                  return(TRUE);
                }
                /*}}}  */
             }
             /*}}}  */
            write_buttons_rc(map,i);
            break;
          }
          /*}}}  */
          /*{{{  kbd*/
          case KBD:
             if (kbd_code()) return(TRUE);
             break;
          /*}}}  */
          /*{{{  define the name of this binding*/
          case BINDNAME: {
            if (named) {
              error_po();
              fprintf(stderr,M_DUPKEY);
              return(TRUE);
            }
            named=TRUE;
            if (!name_parse(name,M_KEYNAME)) return(TRUE);
            if (write_name_rc(tk_string)) return(TRUE);
            if (end_parse(M_WANTEND)) return(TRUE);
            break;
          }
          /*}}}  */
          /*{{{  defmark*/
          case DEFMARK: {
            int i,j;
            char marks[4][tag_length-1];
            char mark_name[name_lg];

            if (!name_parse(mark_name,M_MARKNAME)) return(TRUE);
            /*{{{  get all mark_characters*/
            if (begin_parse()) return(TRUE);
            /*{{{  get all tags*/
            for (i=0;i<4;i++) {
              if (begin_parse()) return(TRUE);
              /*{{{  get tag_length-1 chars*/
              for (j=0;j<(tag_length-1);j++) {
                /*{{{  no char -> error*/
                if (get_token(TRUE)!=CHAR) {
                  error_po();
                  fprintf(stderr,M_WANTCHAR);
                  return(TRUE);
                }
                /*}}}  */
                marks[i][j]=tk_char;
              }
              /*}}}  */
              if (end_parse(M_WANTEND)) return(TRUE);
            }
            /*}}}  */
            if (end_parse(M_WANTEND)) return(TRUE);
            /*}}}  */
            if (end_parse(M_WANTEND)) return(TRUE);
            write_mark_rc(mark_name,marks);
            break;
          }
          /*}}}  */
          /*{{{  defset*/
          case DEFSET: {
            if (parse_set()) return(TRUE);
            if (end_parse(M_WANTEND)) return(TRUE);
            break;
          }
          /*}}}  */
          /*{{{  defvar*/
          case DEFVAR:
           { tokens to;

             if (begin_parse()) return(TRUE);
             while ((to=name_to_var(get_token(FALSE),TRUE))!=END)
                if (to!=VARIABLE)
                 { error_po();
                   fprintf(stderr,M_NOVAR);
                   return(TRUE);
                 }
             if (end_parse(M_WANTEND)) return(TRUE);
             break;
           }
          /*}}}  */
          /*{{{  undeclare*/
          case UNDECLARE:
           { tokens to;
             static char undef[]="(undef)";

             if (begin_parse()) return(TRUE);
             while ((to=get_token(FALSE))!=END)
                switch (to)
                 { case OPERATION:
                      free(tk_operation->op_name);
                      tk_operation->op_name=undef;
                      break;
                   case VARIABLE:
                      free(tk_var->var_name);
                      tk_var->var_name=undef;
                      break;
                   case OPCODE:
                      tk_key->name=undef;
                      break;
                   default:
                    { error_po();
                      fprintf(stderr,M_NOVAR);
                      return(TRUE);
                    }
                 }
             if (end_parse(M_WANTEND)) return(TRUE);
             break;

           }
          /*}}}  */
          /*{{{  defmodestring*/
          case DEFMODE: {
            char str[2][name_lg];
            int i;

            /*{{{  space free?*/
            if (used_modes==MODE_COUNT) {
              error_po();
              fprintf(stderr,M_MANYMODES);
              return(TRUE);
            }
            /*}}}  */
            /*{{{  read name*/
            if (!name_parse(name,M_UMNAME)) return(TRUE);
            for (i=0;i!=used_modes;i++)
               if (!strcmp(tk_string,modenames[i]))
                { error_po();
                  fprintf(stderr,M_UMNAME);
                  return(TRUE);
                }
            if (!(modenames[used_modes]=malloc(strlen(tk_string)+1))) {
              error_po();
              fprintf(stderr,M_NOMEMORY);
              return(TRUE);
            }
            strcpy(modenames[used_modes],tk_string);
            /*}}}  */
            /*{{{  scan the two string*/
            for (i=0;i<2;i++) {
              if (get_token(FALSE)!=MACRO)
               /*{{{  return error*/
               { error_po();fprintf(stderr,M_MSTR);return(TRUE); }
               /*}}}  */
              strcpy(str[i],tk_string);
            }
            /*}}}  */
            if (write_ums_rc(used_modes++,str[0],str[1])) return(TRUE);
            if (end_parse(M_WANTEND)) return(TRUE);
            /*{{{  verbose?*/
            if (verbose) fprintf(stderr,F_DEFMOD,used_modes-1,str[0],str[1]);
            /*}}}  */
            break;
          }
          /*}}}  */
          /*{{{  opcodes or default error*/
          case OPCODE:
           { if (tk_key->num==O_TITLE_HIDE)
              { rc_put_c(RC_NO_TITLE,rc);
                if (!end_parse(M_WANTEND)) break;
              }
           }
          default:
            error_po();
            fprintf(stderr,M_COMMANDLINE);
            return(TRUE);
          /*}}}  */
        }
        break;
      }
      /*{{{  default=error*/
      default:
        error_po();
        fprintf(stderr,M_NOKCOMMAND);
        return(TRUE);
      /*}}}  */
    }
    /*}}}  */
  while ((token=get_token(FALSE))!=ENDFILE);
  if (verbose) fprintf(stderr,"-----------------\n");
  /*{{{  check forward-declarations*/
  { OP **act=new_op;

    while (*act) {
      if (!(*act)->def) {
        fprintf(stderr,F_DNDMAC,(*act)->op_name);
        return(TRUE);
      }
      act++;
    }
  }
  /*}}}  */
  /*{{{  check mkbd-defines*/
  if (mkbd_check()) return(TRUE);
  /*}}}  */
  /*{{{  write sets*/
  if (!dest_mac && writesets(rc)) return(TRUE);
  /*}}}  */
  /*{{{  write keyboards*/
  if (write_kbds()) return(TRUE);
  /*}}}  */
  /*{{{  write number of used macros*/
  put_mac_count(macro_pos);
  /*}}}  */
  return(FALSE);
}
/*}}}  */
