/*{{{}}}*/
/*{{{  #includes*/
#include <ctype.h>
#include <sys/types.h>
#include <limits.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>

#define SCANNER_C

#include "keybind.h"

#include <h/rcformat.h>
#include <h/envvar_str.h>
#include <lib/ori_rc_lib.h>
#include <lib/ori_add_lib.h>
/*}}}  */

/*{{{  typedefs*/
typedef struct { int line,col,input;boolean nl; } t_read_data;
/*}}}  */
/*{{{  variable declarations*/
/*{{{  stack for filed-folds*/
private t_read_data po_stack[OCL_FILE_DEPTH+1];
private LOC_FILE file_stack[OCL_FILE_DEPTH+1];
private unsigned char *name_stack[OCL_FILE_DEPTH+1];
private int f_s_ptr=0;
/*}}}  */
/*{{{  reading-stuff*/
private t_read_data read_data={ 1,0,EOF,False };
/*}}}  */
private boolean err_marked;
public boolean err_pos_out=False;
/*{{{  return-vars for the scanner*/
public unsigned char tk_char;
public KEYNAME *tk_key;
public OP_LIST *tk_operation;
public VARS_LIST const *tk_var;
public int tk_val;
public unsigned char tk_string[NAME_LG];
public TOKEN tk_macro[OCL_CODE_LEN];
/*}}}  */
/*{{{  tables*/
public unsigned char const undef[]="(undef)";
public VARS_LIST const *var_list=0;
public int repeat_var;
public int return_var;
public int rel_op_var;
public OP_LIST new_op= { (unsigned char*)undef,False,True,0,0,0,0,0 };
public unsigned char *source;
/*}}}  */
/*{{{  if-using stuff*/
/*{{{  type TAG_LIST*/
typedef struct TAG_LIST
 { unsigned char const *tag;
   boolean malloced;
   const struct TAG_LIST *next;
 } TAG_LIST;
/*}}}  */
private int missing_gnisu=0;
private TAG_LIST *tag_list=0;
/*}}}  */
/*}}}  */

/*{{{  error_po*/
public void error_po(void)
{
  if (err_pos_out)
   { int i=0;
     
     if (!err_marked)
      { if (verbose_level>0)
           fprintf(stderr,"\n");
        for (;i<=f_s_ptr;i++)
           fprintf
            ( stderr,
              F_ERRORPO,
              (i?name_stack[i]:source),
              (i==f_s_ptr?read_data.line:po_stack[i].line-1)
            );
        fprintf(stderr,F_ERRY,read_data.col);
      }
     err_marked=True;
   }
}
/*}}}  */
/*{{{  create an operation entry*/
public void creat_op(unsigned char *name,boolean mode,int lg,TOKEN *code,int place,boolean ret_used,int args)
{ OP_LIST *op;

  /*{{{  new node to list*/
  op=kbd_malloc(sizeof(OP_LIST));
  op->next=new_op.next;
  new_op.next=op;
  /*}}}  */
  /*{{{  name to node*/
  op->op_name=kbd_malloc(ustrlen(name)+1);
  ustrcpy(op->op_name,name);
  /*}}}  */
  op->args=args;
  op->length=lg;
  op->def=mode;
  op->place=place;
  op->ret_used=ret_used;
  /*{{{  code to node*/
  op->ops=kbd_malloc((1+lg)*sizeof(TOKEN));
  memcpy(op->ops,code,lg*sizeof(int));
  /*}}}  */
  /*{{{  verbose-handling*/
  if (verbose_level>0)
     if (place<0)
       fprintf(stderr,F_OPERATION,name,args,lg);
     else
       fprintf(stderr,F_BELONGS,name,args);
  /*}}}  */
}
/*}}}  */
/*{{{  undeclare a operation*/
public void free_op(unsigned char *name)
{ OP_LIST *op;

  /*{{{  set op to list entry, if given*/
  op= &new_op;
  while (op && ustrcmp(op->op_name,name)) op=op->next;
  /*}}}  */
  if (op)
   { OP_LIST *on;

     kbd_free(op->op_name);
     kbd_free(op->ops);
     on=op->next;
     if (on)
      { *op= *on;
        kbd_free(on);
      }
     else
        op->op_name=(unsigned char*)undef;
   }

}
/*}}}  */
/*{{{  create an variable entry*/
public int creat_var(unsigned char *name,int size,int no)
{ VARS_LIST *vp;

  /*{{{  maybe get new variable number*/
  if (no<0)
   { no=var_count;
     var_count+=size;
   }
  /*}}}  */
  /*{{{  new node to list*/
  vp=kbd_malloc(sizeof(VARS_LIST));
  vp->next=var_list;
  var_list=vp;
  /*}}}  */
  /*{{{  name to node*/
  vp->var_name=(unsigned char const*)mstrcpy(name);
  /*}}}  */
  if (commenting && !dest_mac)
   /*{{{  comment this var in rc file*/
   { char x[NAME_LG*2];
     char *xp;

     sprintf(xp=x,"%d=%s",no,name);
     rc_put_c(RC_COMMENT,rc.fp);
     do rc_put_c(*xp,rc.fp); while (*xp++);
   }
   /*}}}  */
  vp->no=no;
  vp->size=size;

  return(no);
}
/*}}}  */
/*{{{  undeclare a variable*/
public void free_var(unsigned char const*const name)
{ VARS_LIST *vp;

  /*{{{  set vp to list entry, if given*/
  for
   ( vp=(VARS_LIST*)var_list
   ; vp && ustrcmp(vp->var_name,name)
   ; vp=(VARS_LIST*)vp->next
   );
  /*}}}  */
  if (vp)
   /*{{{  remove the var from the list*/
   { VARS_LIST const *vn;

     kbd_free((char*)vp->var_name);
     vn=vp->next;
     if (vn)
      /*{{{  trailling copy nodes and free a node*/
      { *vp= *vn;
        kbd_free((char*)vn);
      }
      /*}}}  */
     else
        vp->var_name=undef;
   }
   /*}}}  */
}
/*}}}  */
/*{{{  init_vars*/
public void init_vars(int no_dummy)
{ int i;

  /*{{{  std-vars, maybe added to rc-file*/
  var_scr_w=     creat_var((unsigned char*)SCR_W,1,-1);
  var_off_w=     creat_var((unsigned char*)SCR_W_O,1,-1);
  var_scr_h=     creat_var((unsigned char*)SCR_H,1,-1);
  var_off_h=     creat_var((unsigned char*)SCR_H_O,1,-1);
  var_cur_lev=   creat_var((unsigned char*)CURSOR_LEVEL,1,-1);
  var_ocl_arg=   creat_var((unsigned char*)OCL_ARG_RECORD_V,DIM_OCL_CMD_OPTS,-1);
                 creat_var((unsigned char*)OCL_ARG_V,1,var_ocl_arg);
  var_file_no=   creat_var((unsigned char*)F_N_VAR,1,-1);
  var_us_buff=   creat_var((unsigned char*)U_B_VAR,1,-1);
  var_cu_buff=   creat_var((unsigned char*)C_B_VAR,1,-1);
  var_cu_b_id=   creat_var((unsigned char*)C_BI_VAR,1,-1);
  var_m_edit=    creat_var((unsigned char*)M_B_VAR,1,-1);
  var_mod_beh=   creat_var((unsigned char*)M_O_VAR,1,-1);
  var_key_count= creat_var((unsigned char*)K_C_VAR,1,-1);
  var_kill_count=creat_var((unsigned char*)KI_C_VAR,1,-1);
  var_move_count=creat_var((unsigned char*)M_C_VAR,1,-1);
  var_path=      creat_var((unsigned char*)VAR_PATH_SEP,1,-1);
  var_m_x=       creat_var((unsigned char*)MOUSE_X,1,-1);
  var_m_y=       creat_var((unsigned char*)MOUSE_Y,1,-1);
  var_m_gy=      creat_var((unsigned char*)MOUSE_G,1,-1);
  var_m_out=     creat_var((unsigned char*)MOUSE_O,1,-1);
  var_m_but=     creat_var((unsigned char*)MOUSE_B,1,-1);
  var_m_buff=    creat_var((unsigned char*)MOUSE_W,1,-1);
  var_dired=     creat_var((unsigned char*)DIRED_VAR,1,-1);
  var_force_sh=  creat_var((unsigned char*)FORCE_SH,1,-1);
  /*}}}  */
  repeat_var=creat_var((unsigned char*)"(repeat)",1,-1);
  return_var=creat_var((unsigned char*)"(return)",1,-1);
  rel_op_var=creat_var((unsigned char*)"(rel_op)",1,-1);
  for (i=0;i<no_dummy;dummy_var(i++));
  def_ocl_args(ocl_std_args);
# ifdef OS_VARS
     OS_VARS
# endif
}
/*}}}  */
/*{{{  use_tag*/
public void use_tag(unsigned char const * const tag, boolean const m)
{ TAG_LIST *tp;

  tp=kbd_malloc(sizeof(TAG_LIST));
  tp->next=tag_list;
  tag_list=tp;
  tp->tag=(tp->malloced=m)
            ? tp->tag=(unsigned char const*)mstrcpy(tag)
            : tag;

}
/*}}}  */
/*{{{  default_using*/
public void default_using(void)
{
  if (ustrcmp(m_name,(unsigned char*)NO_MOUSE))
   { use_it((unsigned char*)"MOUSY");
     use_it(m_name);
   }
  OS_USINGS
}
/*}}}  */
/*{{{  read a character from input, count lines (with look-ahead)*/
#define raw_read_in() (read_data.input=getc(in.fp))
#define in_line_read_in() (read_data.col++,raw_read_in())
private void read_in(void)
{
  if (read_data.nl)
   { read_data.line++;
     read_data.col=0;
   }
  else
     read_data.col++;
  switch (raw_read_in())
   { case '\n':
        read_data.nl=True;
        break;
     case '\t':
        m_error_po(M_TAB);
     default:
        read_data.nl=False;
   }
}
/*}}}  */
/*{{{  init_scan*/
public int ctrl_c[O_NOP];

public void init_scan (void)
{ int i;

  read_in();
  for (i=0;i<O_NOP;i++)
     ctrl_c[i]=0;
  for (i=0;i<32;i++)
   { char c;

     c=CTRL_CHARS[i];
     ctrl_c[c]=i;
     if (isupper(c))
        ctrl_c[tolower(c)]=i;
     if (islower(c))
        ctrl_c[toupper(c)]=i;
   }
  ctrl_c['?']=127;
  ctrl_c[HZ_TILDE]='~';
}
/*}}}  */
/*{{{  get token*/
/*{{{  enum scan_class*/
typedef enum
 {
   /*{{{  basic bit coded scan parts*/
   char_scan=		1<<1,
   key_scan=		1<<2,
   ctrl_scan=		1<<3,
   file_scan=		1<<4,
   keyword_scan=	1<<5,
   opcode_scan=		1<<6,
   number_scan=		1<<7,
   ref_id_scan=		1<<8,
   operation_scan=	1<<9,
   var_scan=		1<<10,
   lang_scan=		1<<11,
   opp_scan=		1<<12,
   skip_file_scan=	1<<13,
   /*}}}  */
   /*{{{  complex scan types*/
   filename_scanning=	file_scan,
   full_scanning=	(   char_scan
   			  | keyword_scan
   			  | opcode_scan
   			  | number_scan
   			  | operation_scan
   			  | var_scan
   			  | lang_scan
   			),
   char_or_key_scanning=(   char_scan
   			  | keyword_scan
   			),
   single_scanning=	( char_scan ),
   name_scanning=	( char_scan ),
   number_scanning=	( number_scan ),
   key_scanning=	(   char_scan
   			  | key_scan
   			),
   skip_scanning=	(   char_scan
   			  | skip_file_scan
                          | ctrl_scan
   			),
   skip_c_or_k_scanning=(   char_scan
   			  | keyword_scan
   			  | ctrl_scan
   			),
   ref_id_scanning=	(   number_scan
   			  | ref_id_scan
   			),
   /*}}}  */
   dummy_scan
 } scan_class;
/*}}}  */
/*{{{  get a token*/
/*{{{  get a token and handle filed-folds - filed-folds are handled inside*/
/*{{{  get a token from current input-file*/
private tokens get_token_from_file(scan_class type)
{
  unsigned char *s;

  err_marked=False;
  /*{{{  skip comments, spaces  ...*/
  for (;;read_in())
   { switch (read_data.input)
      { case '\n':
        case ' ':
           continue;
        default:
           if
            (    read_data.input==';'
              || read_data.input==BEGIN_STANDARD[0]
              || read_data.input==END_STANDARD[0]
            )
            /*{{{  skip comment line*/
            { for (;;)
               { switch (read_data.input)
                  { case '\n':
                    case EOF:
                       read_data.nl=True;
                       break;
                    default:
                       raw_read_in();
                       continue;
                  }
                 break;
               }
              continue;
            }
            /*}}}  */
           else
              break;
      }
     break;
   }
  /*}}}  */
  /*{{{  maybe error if tab*/
  if (read_data.input=='\t' && !(type&ctrl_scan))
     return(ERROR);
  /*}}}  */
  /*{{{  maybe scan char tokens + - ..*/
  if (type&char_scan)
     switch(read_data.input)
      { case EOF:       read_in();return(ENDFILE);
        case '(':       read_in();return(BEGIN);
        case ')':       read_in();return(END);
        case ',':       read_in();return(COMMA);
        case '@':       read_in();return(COMPPRE);
        case '+':       read_in();return(ADD);
        case '-':       read_in();return(MINUS);
        case '*':       read_in();return(MULT);
        case '=':       read_in();return(REL_EQ);
        case '<':
           read_in();
           switch(read_data.input)
            { case '>':	read_in();return(REL_NEQ);
              case '=':	read_in();return(REL_LOW_EQ);
              default:	          return(REL_LOW);
            }
        case '>':
           read_in();
           switch (read_data.input)
            { case '=':	read_in();return(REL_HIGH_EQ);
              default:	          return(REL_HIGH);
            }
      }
  /*}}}  */
  /*{{{  maybe scan key-codes*/
  if (type&key_scan)
     switch (read_data.input)
      {
        /*{{{  hex-value*/
        case '0':
         { int h=0;
           unsigned char *s=tk_string;

           read_in();
           if (read_data.input!='x' && read_data.input!='X')
              m_exit(M_NOHEX);
           read_in();
           *s++='0';
           *s++='x';
           for (;;)
            { switch(read_data.input)
               { case '0': h=h*16;   break;
                 case '1': h=h*16+1; break;
                 case '2': h=h*16+2; break;
                 case '3': h=h*16+3; break;
                 case '4': h=h*16+4; break;
                 case '5': h=h*16+5; break;
                 case '6': h=h*16+6; break;
                 case '7': h=h*16+7; break;
                 case '8': h=h*16+8; break;
                 case '9': h=h*16+9; break;
                 case 'a': h=h*16+10;break;
                 case 'A': h=h*16+10;break;
                 case 'b': h=h*16+11;break;
                 case 'B': h=h*16+11;break;
                 case 'c': h=h*16+12;break;
                 case 'C': h=h*16+12;break;
                 case 'd': h=h*16+13;break;
                 case 'D': h=h*16+13;break;
                 case 'e': h=h*16+14;break;
                 case 'E': h=h*16+14;break;
                 case 'f': h=h*16+15;break;
                 case 'F': h=h*16+15;break;
                 default:  tk_char=h;*s++=' ';*s='\0';return(HEX);
               }
              *s++=read_data.input;
              read_in();
            }
         }
        /*}}}  */
        /*{{{  Meta-handling*/
        case 'M':
         { in_line_read_in();
           if (read_data.input!='-')
              m_exit(M_NOMETA);
           read_in();
           return(META);
         }
        /*}}}  */
        /*{{{  Control-handling*/
        case 'C':
         { in_line_read_in();
           if (read_data.input!='-')
              m_exit(M_NOCNTRL);
           read_in();
           tk_char=ctrl_c[read_data.input];
           read_in();
           return(CHAR);
         }
        /*}}}  */
        /*{{{  Char-handling*/
        case '"':
         { in_line_read_in();
           if (read_data.input<' ' || read_data.input>127)
              m_exit(M_NOCHAR);
           tk_char=read_data.input;
           read_in();
           return(CHAR);
         }
        /*}}}  */
        /*{{{  Alias-handling*/
        case '$':
         { unsigned char *s=tk_string;

           /*{{{  read name*/
           in_line_read_in();
           for (;;)
            { switch (read_data.input)
               { case '\n':
                    read_data.nl=True;
                 case ' ':
                 case ')':
                 case EOF:
                    *s='\0';
                    break;
                 default:
                    *s++=read_data.input;
                    in_line_read_in();
                    continue;
               }
              break;
            }
           /*}}}  */
           return(DOLLAR);
         }
        /*}}}  */
        /*{{{  default=error*/
        default :
           m_exit(M_NOCODE);
        /*}}}  */
      }
  /*}}}  */
  if (read_data.input=='\"')
   /*{{{  string-handling*/
    { TOKEN *t=tk_macro;
      unsigned char  *c=tk_string;

      in_line_read_in();
      for (;;)
       { if (c>=(tk_string+NAME_LG-1))
            m_exit(M_LONG_MACRO);
         /*{{{  Test auf < ' ' oder EOF*/
         if (read_data.input<' ' || read_data.input==EOF)
            if (!(type&ctrl_scan))
               m_exit(M_FALSEEND);
            else if (read_data.input=='\n')
               break;
         /*}}}  */
         *t++ = (TOKEN) read_data.input;
         *c++ = (unsigned char) read_data.input;
         in_line_read_in();
         switch (read_data.input)
          { case '\n':
               read_data.nl=True;
            case ' ':
            case ')':
            case '"':
            case EOF:
               break;
            default:
               continue;
          }
         break;
       }
      *t= (TOKEN) 0;
      *c= '\0';
      return(MACRO);
    }
   /*}}}  */
  else
   /*{{{  handle identifier*/
   {
     /*{{{  read given identifier*/
     for (s=tk_string;;)
      { switch ((*s++=read_data.input))
         { case '\n':
              read_data.nl=True;
           case ' ':
           case ')':
           case ',':
           case '(':
           case ';':
           case EOF:
              *--s='\0';
              break;
           default:
              in_line_read_in();
              continue;
         }
        break;
      }
     /*}}}  */
     if (type&file_scan)
        return(NAME);
     if (type&keyword_scan)
      /*{{{  search as keyword*/
      { keywords const *k;

        if ((k=name2keyword(tk_string)))
           return(k->value);
      }
      /*}}}  */
     if (type&opcode_scan)
      /*{{{  search as opcode*/
        if ((tk_key=name2func(tk_string)))
           return(OPCODE);
      /*}}}  */
     if (type&number_scan)
      /*{{{  is it a number*/
      { s=tk_string;
        while (*s && isdigit(*s)) s++;
        if (!*s)
         { tk_val=atoi((char*)tk_string);
           return(NUMBER);
         }
      }
      /*}}}  */
     if (type&(ref_id_scan|number_scan))
      /*{{{  search as refcard-level*/
      { static struct ref_list
         { struct ref_list *next;
           int no;
           unsigned char name[1];
         } *ref_names=0,*x;

        /*{{{  look if already defined*/
        for (x=ref_names,tk_val=1;x;x=x->next)
           if (!ustrcmp(x->name,tk_string))
            { tk_val=x->no;
              return(NUMBER);
            }
           else if (x->no>=tk_val)
              tk_val++;
        /*}}}  */
        if (type&ref_id_scan)
         /*{{{  define new*/
         { x=kbd_malloc(sizeof(struct ref_list)+strlen((char*)tk_string));
           x->no=tk_val;
           ustrcpy(x->name,tk_string);
           x->next=ref_names;
           ref_names=x;
           return(NUMBER);
         }
         /*}}}  */
      }
      /*}}}  */
     if (type&operation_scan)
      /*{{{  search as operation*/
      { for
         ( tk_operation= &new_op;
              tk_operation
           && ustrcmp(tk_operation->op_name,tk_string);
           tk_operation=tk_operation->next
         );
        if (tk_operation) return(OPERATION);
      }
      /*}}}  */
     if (type&var_scan)
      /*{{{  search as variable*/
      { for
         ( tk_var=var_list;
           tk_var && ustrcmp(tk_var->var_name,tk_string);
           tk_var=tk_var->next
         );
        if (tk_var) return(VARIABLE);
      }
      /*}}}  */
     if (type&lang_scan)
      /*{{{  search as language*/
      { unsigned char c=name2lg(tk_string);

        if (c)
         { tk_string[0]=c;
           tk_string[1]='\0';
           tk_macro[0]=(TOKEN)c;
           tk_macro[1]=0;
           return(MACRO);
         }
      }
      /*}}}  */
     if (type&opp_scan)
      /*{{{  look for fi/if-using*/
      { if (!ustrcmp(tk_string,fi_name)) return(FI);
        if (!ustrcmp(tk_string,if_u_name)) return(COMPIF);
      }
      /*}}}  */
     return(NAME);
   }
   /*}}}  */
}
/*}}}  */

private tokens get_ff_token(scan_class type)
{ static tokens push_back=ENDFILE;
  tokens t;

  if (push_back!=ENDFILE)
   /*{{{  return old value*/
   { tokens x;

     x=push_back;
     push_back=ENDFILE;
     return(x);
   }
   /*}}}  */
  switch ((t=get_token_from_file(type)))
   {
     /*{{{  True/False*/
     case TRUE_SYM:
     case FALSE_SYM:
        tk_val=(t==TRUE_SYM)?1:0;
        return(NUMBER);
     /*}}}  */
     /*{{{  O_CALL_FIX*/
     case OPCODE:
        if (tk_key->num==O_CALL_FIX)
         /*{{{  handle numbered macro-calls*/
         { static KEYNAME x;
           static unsigned char na[NAME_LG];

           x.name=na;
           ustrcpy(na,tk_key->name);
           strcat((char*)na," ");
           /*{{{  get correct buffer-place*/
           switch (get_token_from_file(type))
            {
              /*{{{  number*/
              case NUMBER:
               { x.num=O_CALL_FIX+tk_val+1;
                 break;
               }
              /*}}}  */
              /*{{{  defined macro*/
              case OPERATION:
               { if (tk_operation->place)
                  { x.num=O_CALL_FIX+tk_operation->place+1;
                    break;
                  }
               }
              /*}}}  */
              /*{{{  else error*/
              default:
                 m_exit(M_NOADDCOUNTER);
              /*}}}  */
            }
           if (x.num<0)
            { error_po();
              return(ERROR);
            }
           /*}}}  */
           ustrcat(na,tk_string);
           if (x.num>(mac_count+O_EXE_MACRO-2))
              mac_count=x.num-O_EXE_MACRO+2;
           tk_key= &x;
           return(OPCODE);
         }
         /*}}}  */
        else
           return(t);
     /*}}}  */
     /*{{{  ENDFILE -> goto upper level, if any*/
     case ENDFILE:
        if (f_s_ptr)
         {
           /*{{{  verbose message, part 1*/
           if (verbose_level>2)
            { fprintf(stderr,F_EX_FILE_1,name_stack[f_s_ptr]);
              fflush(stderr);
            }
           /*}}}  */
           /*{{{  pop file from stack*/
           clear_file(&in);
           kbd_free(name_stack[f_s_ptr]);
           read_data=po_stack[--f_s_ptr];
           in=file_stack[f_s_ptr];
           /*}}}  */
           /*{{{  verbose message, part 2*/
           if (verbose_level>2)
            { fprintf
               ( stderr,
                 F_EX_FILE_2,
                 f_s_ptr?name_stack[f_s_ptr]:source,
                 read_data.line
               );
              fflush(stderr);
            }
           /*}}}  */
           return(get_ff_token(type));
         }
        else
           return(ENDFILE);
     /*}}}  */
     /*{{{  INCLUDE or lib -> go to lower level*/
     case COMPPRE:
        switch ((t=get_token_from_file(char_or_key_scanning)))
         { case LIB:
              break;
           case NAME:
              if (!ustrcmp(tk_string,include_name))
                 break;
           default:
              push_back=t;
              return(COMPPRE);
         }
     case INCLUDE:
       if (!(type&skip_file_scan))
        { char *path=((t==LIB)?lib_path:CURR_DIR);

          /*{{{  check if correct include*/
          if (get_token_from_file(filename_scanning)!=NAME)
             m_exit(M_NOFNAME);
          if (f_s_ptr==OCL_FILE_DEPTH)
           { fprintf(stderr,M_DEPTH);
             return(ERROR);
           }
          /*}}}  */
          /*{{{  verbose handling, part 1*/
          if (verbose_level>2)
           { fprintf
              ( stderr,
                F_ENT_FILE_1,
                f_s_ptr?name_stack[f_s_ptr]:source,
                read_data.line
              );
             fflush(stderr);
           }
          /*}}}  */
          /*{{{  store file-info*/
          po_stack[f_s_ptr]=read_data;
          file_stack[f_s_ptr++]=in;
          name_stack[f_s_ptr]=mstrcpy(tk_string);
          /*}}}  */
          /*{{{  open file*/
          { char pushfile[_POSIX_PATH_MAX];

            if (!IS_ROOT((char*)tk_string))
             { for (;;)
                  if(path_file_test(pushfile,&path,(char*)tk_string,""))
                     break;
                  else if (!*path)
                     goto no_include;
             }
            else
               strcpy(pushfile,(char*)tk_string);

            if (!open_source(&in,(unsigned char*)pushfile,False))

          no_include:
           { in=file_stack[--f_s_ptr];
             fprintf(stderr,F_INCLUDE,tk_string);
             return(ERROR);
           }
          }
          /*}}}  */
          /*{{{  start reading*/
          read_data.line=1;
          read_data.col=0;
          read_data.input=' ';
          read_data.nl=False;
          read_in();
          /*}}}  */
          /*{{{  verbose handling, part 2*/
          if (verbose_level>2)
           { fprintf(stderr,F_ENT_FILE_2,tk_string);
             fflush(stderr);
           }
          /*}}}  */
          return(get_ff_token(type));
        }
     /*}}}  */
     default: return(t);
   }
}
/*}}}  */
/*{{{  tag_handling*/
/*{{{  comment*/
/*
  set=True: the tags in list are set
            return=-1: syntax-error
            return=0:  tag is set
            return=1:  tag was already set
           if the list starts with ``not'', the return-values 1 and o
           are exchanged!
 set=False: look, if one of the listed tags is set
            return=-1: syntax-error
            return=0:  no set tag found
            return=1:  one of the tags is set
*/
/*}}}  */
private int tag_handling(boolean set)
{
  boolean found=False;
  boolean reverse=False;

  /*{{{  correct begin given?*/
  switch (get_ff_token(char_or_key_scanning))
   { case NOT:
        if (get_ff_token(char_or_key_scanning)!=BEGIN)
     default:
           m_exit(M_OPPTAG);
        reverse=True;
     case BEGIN:
        break;
   }
  /*}}}  */
  for (;;)
   { switch (get_ff_token(name_scanning))
      { case END:
           break;
        case NAME:
         { boolean local_found;
           TAG_LIST *tp;
         
           /*{{{  look for this tag in taglist*/
           /*
           for (local_found=False,tp= &tags;tp;)
           */ for (local_found=False,tp=tag_list;tp;)
              if (ustrcmp(tk_string,tp->tag))
                 tp=(TAG_LIST*)tp->next;
              else
               { local_found=True;
                 break;
               }
           /*}}}  */
           /*{{{  set and tag not in list, tag->list*/
           if (set && !reverse && !local_found)
            { use_tag(tk_string,True);
              if (verbose_level>3)
                 fprintf(stderr,F_USESET,tk_string);
            }
           /*}}}  */
           /*{{{  unset and tag in list, remove tag from list*/
           if (set && reverse && local_found)
            { TAG_LIST *tn;

              if (tp->malloced)
                 kbd_free((char*)tp->tag);
              if ((tn=(TAG_LIST*)tp->next))
               { *tp= *tn;
                 kbd_free(tn);
               }
              else
                 tp->tag=undef;
              if (verbose_level>3)
                 fprintf(stderr,F_UNSET,tk_string);
            }
           /*}}}  */
           found |= local_found;
           continue;
         }
        default:
           m_exit(M_OPPTAG);
      }
     break;
   }
  if (reverse) return(found ? 0 : 1); else return(found ? 1 : 0);
}
/*}}}  */

private tokens get_token(scan_class type)
{
  tokens t;
  int x;

  for (;;)
   { if ((t=get_ff_token(type))==COMPPRE)
      /*{{{  handle opp-statement*/
      switch (t=get_ff_token(char_or_key_scanning))
       {
         /*{{{  if no set tag listed, overread else store number of missing ends*/
         case COMPIF:
          { x=tag_handling(False);
            if (x)
             { missing_gnisu++;
               /*{{{  very_verbose-message*/
               if (verbose_level>3)
                  fprintf
                   ( stderr,
                     F_USECOMP,
                     missing_gnisu,
                     f_s_ptr?name_stack[f_s_ptr]:source,
                     read_data.line
                   );
               /*}}}  */
             }
            else
             /*{{{  overread the block*/
             { int use_depth;

               /*{{{  very_verbose-message*/
               if (verbose_level>3)
                  fprintf
                   ( stderr,
                     F_IGNORING,
                     missing_gnisu+1,
                     f_s_ptr?name_stack[f_s_ptr]:source,
                     read_data.line
                   );
               /*}}}  */
               use_depth=1;
               t= !ENDFILE;
               while (use_depth && t!=ENDFILE)
                /*{{{  only parse opp-statements if-using/gnisu-fi*/
                if ((t=get_ff_token(skip_scanning))==COMPPRE)
                 { if ((t=get_ff_token(skip_c_or_k_scanning))==COMPIF)
                    { use_depth++;
                      /*{{{  very_verbose-message*/
                      if (verbose_level>4)
                         fprintf
                          ( stderr,
                            F_IGNORING,
                            missing_gnisu+use_depth,
                            f_s_ptr?name_stack[f_s_ptr]:source,
                            read_data.line
                          );
                      /*}}}  */
                    }
                   else if (t==FI)
                    { use_depth--;
                      /*{{{  very_verbose-message*/
                      if (verbose_level>4)
                         fprintf
                          ( stderr,
                            F_NOAGAIN,
                            missing_gnisu+1+use_depth,
                            f_s_ptr?name_stack[f_s_ptr]:source,
                            read_data.line
                          );
                      /*}}}  */
                    }
                 }
                else if (t==ENDFILE)
                   break;
                /*}}}  */
               if (t!=ENDFILE)
                {
                  /*{{{  very_verbose-message*/
                  if (verbose_level>3)
                     fprintf
                      ( stderr,
                        F_AGAIN,
                        missing_gnisu+1,
                        f_s_ptr?name_stack[f_s_ptr]:source,
                        read_data.line
                      );
                  /*}}}  */
                }
               else
                  missing_gnisu++;
             }
             /*}}}  */
            break;
          }
         /*}}}  */
         /*{{{  set tags*/
         case COMPUSE:
            tag_handling(True);
            break;
         /*}}}  */
         /*{{{  print the reference*/
          { unsigned char line[RC_HELP_LEN+2];
            int lg;
            unsigned char *s;
            unsigned char *r;
            int dump;
            int no;


         case STARTREF_NO:
          /*{{{  get number of ref entry*/
          { switch (get_ff_token(ref_id_scanning))
             { case NUMBER:
                  if (tk_val>0 || t<=RC_CLASS_MAX)
                   { no=tk_val;
                     break;
                   }
               default:
                  m_exit(M_OPP);
             }
          }
          /*}}}  */
         case STARTREF:
            for (dump=0;;)
             {
               /*{{{  read line*/
               /*{{{  read the line*/
               s=line;
               lg=RC_HELP_LEN;
               if (t!=STARTREF)
                  lg-=6;
               /*{{{  maybe add last line char*/
               if (dump)
                { *s++=dump;
                  lg--;
                }
               /*}}}  */
               for (;;)
                { switch((dump=raw_read_in()))
                   { case EOF:
                        return(ERROR);
                     case '\n':
                        read_data.line++;
                        read_data.col=0;
                        dump=0;
                        break;
                     case '\t':
                        dump=' ';
                     default:
                        *s=dump;
                        if (lg<=0)
                           break;
                        lg--;
                        s++;
                        continue;
                   }
                  break;
                }
               *s='\0';
               /*}}}  */
               /*{{{  cut trailing spaces*/
               r=s=line;
               while (*r)
                  if (*r!=' ')
                     s= ++r;
                  else
                     r++;
               *s='\0';
               /*}}}  */
               /*}}}  */
               /*{{{  if endref line, break from loop*/
               s=line;
               while (*s==' ') s++;
               if (*s=='@' && !ustrcmp(end_ref,s+1))
                  break;
               /*}}}  */
               if (t==STARTREF)
                /*{{{  normal refcard line*/
                { if (ref.fp)
                   { fputs((char*)line,ref.fp);
                     fputc('\n',ref.fp);
                   }
                }
                /*}}}  */
               else
                /*{{{  numbered refcard line*/
                { if (ref_no.fp)
                   { char tag[REF_TAG_LG+1];

                     ref_code_tag(tag,ref_kbd-no);
                     fprintf
                      ( ref_no.fp,
                        ref_format_str("%s"),
                        tag,
                        line
                      );
                   }
                }
                /*}}}  */
             }
            break;
          }
         /*}}}  */
         /*{{{  line number*/
         case LINENO:
            if (get_ff_token(number_scanning)==NUMBER)
               read_data.line=tk_val;
            else
               m_exit(M_OPP);
            break;
         /*}}}  */
         /*{{{  rc-comment*/
         case COMMENT:
            if (!dest_mac) rc_put_c(RC_COMMENT,rc.fp);
            if (read_data.input==' ') read_in();
            while
             (     read_data.input
                && read_data.input!=EOF
                && read_data.input!='\n'
             )
             { if (!dest_mac) rc_put_c(read_data.input,rc.fp);
               read_in();
             }
            if (!dest_mac) rc_put_c(0,rc.fp);
            break;
         /*}}}  */
         /*{{{  error*/
         case OPP_ERROR:
            error_po();
            while
             (    read_data.input
               && read_data.input!=EOF
               && read_data.input!='\n'
             )
             { fputc(read_data.input,stderr);
               read_in();
             }
            fputc('\n',stderr);
            return(ERROR);
         /*}}}  */
         /*{{{  handle the end of a block*/
         case FI:
            if (missing_gnisu)
             /*{{{  handle the end of a block*/
             { missing_gnisu--;
               /*{{{  very_verbose-message*/
               if (verbose_level>3)
                  fprintf
                   ( stderr,
                     F_USEEND,
                     missing_gnisu+1,
                     f_s_ptr?name_stack[f_s_ptr]:source,
                     read_data.line
                   );
               /*}}}  */
               break;
             }
             /*}}}  */
         /*}}}  */
         default:
         /*{{{  wrong opp-statement*/
           m_exit(t==FI ? M_ENDUSE : M_OPP);
         /*}}}  */
       }
      /*}}}  */
     else
        break;
   }
  /*{{{  check missing fi*/
  if (t==ENDFILE && missing_gnisu)
     m_exit(M_BEGINUSE);
  /*}}}  */
  return(t);
}
/*}}}  */

/*{{{  get_full_token*/
public tokens get_full_token(void)
{
  return(get_token(full_scanning));
}
/*}}}  */
/*{{{  get_keycode_token*/
public tokens get_keycode_token(void)
{
  return(get_token(key_scanning));
}
/*}}}  */
/*{{{  get_single_token*/
public tokens get_single_token(void)
{
  return(get_token(single_scanning));
}
/*}}}  */
/*}}}  */
