/*{{{}}}*/
/*{{{  #includes*/
#ifdef CONFIG_H
#   include "config.h"
#endif

#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

#define INIT_C
#define I_DISPLAY_C
#define I_FOLDING_C
#define I_GETMSG_C
#define I_GETTK_C
#define I_KEYBOARD_C
#define I_KEYTAB_C
#define I_LOOP_C
#define I_MAIN_C
#define I_MISC_C
#define I_MESSAGES_C
#define I_ORIEDT_C
#define I_PROMPT_C
#define I_SCREEN_C
#define I_SET_C
#define I_SIGNALS_C
#define I_VIRTUAL_C

#define I_RC_CHECK

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

/*{{{  variables*/
public char *ori_name=0;
public char const * ori_path=M_RC_PATH;
public off_t helpofs=0;
public off_t compofs=0;
public FILE *rcfile=0;
#ifdef NOMEMDUMP
  public char *mem_dump_malloc;
#endif
/*}}}  */

/*{{{  rcclose*/
public void rcclose(void)
{
  if (rcfile)
   { fclose(rcfile);
     rcfile=0;
   }
}
/*}}}  */
/*{{{  open_sysfile*/
public char *open_sysfile(char const * const ending,char * const name_default)
{
  return
   ( get_system_filename
      ( ori_path,
        ( rc_name
           ? rc_name
           : (char*)get_msg(M_BASE_FORMAT,(unsigned char*)ori_name)
        ),
        ending,
        name_default
      )
   );
}
/*}}}  */
/*{{{  parse rcfile*/
public boolean rcfileparser
 ( char ocl_opt[NO_OCL_CMD_OPTS*(2*BIND_NAME_LEN+2)],
   char *mark_mode
 )
{
  /*{{{  local vars*/
  int input;
  char *ori_term;
  unsigned char u_m_buff[MODE_COUNT*2*(BIND_NAME_LEN+1)];
  unsigned char *u_m_p;
  boolean demand_found=False;
  boolean kbd_read=False;
  char *x;
  /*{{{  RC_BUFFER_SIZE=max(RC_BUFFER_SIZE BUFSIZE)*/
#  ifndef RC_BUFFER_SIZE
#    define RC_BUFFER_SIZE BUFSIZE
#  else
#    if BUFSIZE>RC_BUFFER_SIZE
#       define RC_BUFFER_SIZE BUFSIZE
#    endif
#  endif
  /*}}}  */
  static char rc_io_buff[RC_BUFFER_SIZE];
  /*}}}  */

  /*{{{  open file*/
  { char name[_POSIX_PATH_MAX+1];

    rcclose();
    x=open_sysfile(M_RCSTR,name);
    if (!*x)
     { if (!ocl_opt)
        { eputs(get_msg(M_RF,name));
          eputs(" "STR_MISSING"\n");
        }
       return(True);
     }
    if ((rcfile=fopen(x,(char*)"rb")))
       setvbuf(rcfile,rc_io_buff,_IOFBF,(size_t)RC_BUFFER_SIZE);
  }
  /*}}}  */
  if (!ocl_opt)
   /*{{{  do some initialization*/
   {
     /*{{{  ori_term=ORITERM | TERM | DEFAULT*/
     if
      (    !((ori_term=getenv(ORITERM)) && !ori_term[0])
        && !((ori_term=getenv(TERM)) && !ori_term[0])
      )
#       ifdef DEFAULT_TERM
           ori_term=(char*)DEFAULT_TERM;
#       else
           ori_term=(char*)empty_text;
#       endif
     /*}}}  */
     /*{{{  clear buffer for user mode strings*/
     u_m_p=u_m_buff;
     /*}}}  */
   }
   /*}}}  */
  /*{{{  little rc-file test*/
  if (rc_get_w(rcfile)!=RC_CHECK)
     goto rc_p_error;
  ocl_msg("check %d",RC_CHECK);
  /*}}}  */
  /*{{{  constants*/
  { int i;
    boolean al;

    if (rc_get_c(rcfile)!=RC_CONST)
       goto rc_p_error;
    al=arg_list;
    /*{{{  get constants*/
    rc_nget_w(rcfile,RCC_SIZE,bind_const);
    /*}}}  */
    /*{{{  keyname*/
    rc_nget_c(rcfile,BIND_NAME_LEN,(char*)origami_name);
    origami_name[BIND_NAME_LEN]='\0';
    ocl_msg("keyname",0);
    /*}}}  */
    /*{{{  get options, maybe return, if only options should be read*/
    if (ocl_opt)
     { rc_nget_c(rcfile,NO_OCL_CMD_OPTS*(2*BIND_NAME_LEN+2),ocl_opt);
       ocl_opt[NO_OCL_CMD_OPTS*(2*BIND_NAME_LEN+2)]='\0';
       ocl_opt[NO_OCL_CMD_OPTS*(2*BIND_NAME_LEN+2)+1]='\0';
       rcclose();
       return(False);
     }
    else
       rc_skip_cw(rcfile,NO_OCL_CMD_OPTS*(2*BIND_NAME_LEN+2),0);
    /*}}}  */
    /*{{{  handle vars, hooks and var/mac memory mallocing*/
    {
      /*{{{  handle macs*/
      if
       ( !(fix_macros=paket_malloc(  MAX_MACRO_LENGTH*sizeof(TOKEN)
                                    + (1+mac_count)*sizeof(macro_entry)))
       )
         goto rc_mem_full;
      /*{{{  clear all buffers*/
      { macro_entry *x;

        x=(macro_entry*)fix_macros;
        x->mode=init;
        x->mac.txt=(TOKEN*)&(fix_macros[mac_count+1]);
        for
         ( i=RCC_SIZE-1;
           i--;
           x++,x->mode=init,x->mac.txt=empty_macro
         );
      }
      /*}}}  */
      ocl_msg("macs %d",mac_count);
      /*}}}  */
      /*{{{  handle vars*/
      ocl_msg("vars %d",var_count);
      if (!(ocl_var=calloc(var_count,sizeof(stackent)))) goto rc_mem_full;
      ocl_msg("cy_var %d",var_cur_lev);
      ocl_msg("sy_var %d",var_scr_h);
      ocl_msg("syo_var %d",var_off_h);
      ocl_msg("sx_var %d",var_scr_w);
      ocl_msg("sxo_var %d",var_off_w);
      ocl_msg("ocl_arg %d",var_ocl_arg);
      ocl_msg("uw_var %d",var_us_buff);
      ocl_msg("cw_var %d",var_cu_buff);
      ocl_msg("me_var %d",var_m_edit);
      ocl_msg("mb_var %d",var_mod_beh);
      ocl_msg("kc_var %d",var_key_count);
      ocl_msg("mouse_x %d",var_m_x);
      ocl_msg("mouse_y %d",var_m_y);
      ocl_msg("mouse_b %d",var_m_but);
      ocl_msg("mouse_go_y %d",var_m_gy);
      ocl_msg("mouse_outside %d",var_m_out);
      ocl_msg("mouse_buf %d",var_m_buff);
      ocl_msg("abort key %d",general_abort_key);
      /*}}}  */
      /*{{{  specials*/
      /*{{{  mode limiter*/
      if (comma)
       { ocl_msg("mode limit >%c<",comma); }
      else if (!(comma=get_msg(D_COMMA)[0]))
         comma=MSG_D_COMMA;
      /*}}}  */
      /*{{{  line limiter*/
      if (eoln_str)
       { ocl_msg("lineend mark >%c<",eoln_str); }
      else if (!(eoln_str=get_msg(D_EOLN)[0]))
         eoln_str=MSG_D_EOLN;
      /*}}}  */
      /*{{{  shift mark*/
      if (soln_str)
       { ocl_msg("linestart mark >%c<",soln_str); }
      else if (!(soln_str=get_msg(D_SOLN)[0]))
         soln_str=MSG_D_SOLN;
      if (soln_str==' ')
         soln_str='\0';
      /*}}}  */
      /*}}}  */
      /*{{{  hooks*/
      ocl_msg("auto macro %d",auto_macro);
      ocl_msg("ab_mac %d",abort_macro);
      ocl_msg("knb_mac %d",knb_macro);
      ocl_msg("pin %d",pin_macro);
      ocl_msg("pout %d",pout_macro);
      ocl_msg("v_mac %d",view_macro);
      ocl_msg("bchg_mac %d",buff_macro);
      /*}}}  */
      /*{{{  switches*/
      if (var_notitle) { ocl_msg("no title\n",0); }
      if (arg_list) { ocl_msg("arg_list",0); }
      if (al) arg_list=True;
      /*}}}  */
    }
    /*}}}  */
  }
  /*}}}  */
  /*{{{  read all rc entries*/
  { char t_buff[NAME_LG+1];

    for (;;)
     { switch ((input=rc_get_c(rcfile)))
        {
          /*{{{  ende/reference ->break;*/
          case RC_ENDE:
          case RC_BIND:
             break;
          /*}}}  */
          /*{{{  strings*/
          case RC_STRINGS:
           { int n;
             unsigned char *s;

             if (rc_msg)
                goto rc_p_error;
             rc_msg_count=rc_get_w(rcfile);
             n=rc_get_w(rcfile);
             if (!(rc_msg=paket_malloc(rc_msg_count*sizeof(unsigned char*)+n)))
                goto rc_mem_full;
             s=(unsigned char*)((unsigned char**)rc_msg+rc_msg_count);
             rc_nget_c(rcfile,n,(char*)s);
             for (n=rc_msg_count;n--;)
              { rc_msg[n]=s;
                while (*s++);
              }
             continue;
           }
          /*}}}  */
          /*{{{  termalias*/
          case RC_TERMALIAS:
           { char tname[NAME_LG+1];
             int ch;
             boolean found;
           
             found=False;
             while ((ch=rc_get_c(rcfile)) && ch!=EOF)
              /*{{{  look for a alias*/
              { int l;

                rc_get_s(rcfile,tname,NAME_LG+1);
                if (tname[l=(strlen(tname)-1)]=='*')
                 { if (!strncmp(ori_term,tname,l-1)) found=True; }
                else
                 { if (!strcmp(ori_term,tname)) found=True; }
              }
              /*}}}  */
             /*{{{  get the replace term*/
             rc_get_s(rcfile,tname,NAME_LG+1);
             /*}}}  */
             if (found) strcpy(ori_term=t_buff,tname);
             ocl_msg("termalias replaced %d",found);
             continue;
           }
          /*}}}  */
          /*{{{  keydef*/
          case RC_DEFKEY:
           { char kname[NAME_LG+1];
             int nodes;

             if (ktb_count<=0)
                goto rc_p_error;
             rc_get_s(rcfile,kname,NAME_LG+1);
             nodes=rc_get_w(rcfile);
             if
              /*{{{  kbd not read and (term matches or default)*/
              (!kbd_read && (kname[0]=='\0' || !strcmp(kname,ori_term)))
              /*}}}  */
              /*{{{  read the table*/
              { KEY *tp;
                KEY const *top;
                int *m;

                kbd_read=True;
                /*{{{  get space for table and bind_marks*/
                if
                 (    !(top=tp=paket_malloc(nodes*sizeof(KEY)))
                   || !(m=paket_malloc(ktb_count*sizeof(int)))
                 )
                   goto rc_mem_full;
                /*}}}  */
                /*{{{  read all help marks*/
                rc_nget_w(rcfile,ktb_count,(int*)m);
                /*}}}  */
                /*{{{  read all nodes*/
                while (nodes--)
                 { set_key_data(tp,rcfile);
                   tp++;
                 }
                /*}}}  */
                set_key_top(top,m);
              }
              /*}}}  */
             else
              /*{{{  don't read*/
              { rc_skip_cw(rcfile,nodes*2,nodes+ktb_count);
                ocl_msg("keydef %d skip",nodes);
              }
              /*}}}  */
             continue;
           }
          /*}}}  */
          /*{{{  usermodestrings*/
          case RC_MODE:
           { int no;
             int off;

             no=rc_get_c(rcfile);
             /*{{{  get long and short form*/
             for (off=MODE_COUNT;off>=0;off-=MODE_COUNT)
              { int m_lg;

                m_lg=rc_get_w(rcfile);
                if (m_lg)
                 { u_modes[no+off]=u_m_p;
                   rc_nget_c(rcfile,m_lg,(char*)u_m_p);
                   u_m_p+=m_lg;
                   *u_m_p++='\0';
                 }
              }
             /*}}}  */
             if (!u_modes[no])
                u_modes[no]=u_modes[no+MODE_COUNT];
             ocl_msg("user mode %d",no);
             continue;
           }
          /*}}}  */
          /*{{{  macset*/
          case RC_MAC_SET:
           { int lg;
             TOKEN *t;

             lg=rc_get_w(rcfile);
             t=paket_malloc(lg*sizeof(TOKEN));
             if (!t) goto rc_mem_full;
             ocl_msg("mac paket %d\n",lg);
             do
              /*{{{  get one mac*/
              { int ml;
                int no;

                no=rc_get_w(rcfile);
                ml=rc_get_w(rcfile);
                ocl_msg("  mac %d\n",no);
                if (no>mac_count || no<=0)
                   goto rc_p_error;
                ((macro_entry*)fix_macros)[no].mode=def;
                ((macro_entry*)fix_macros)[no].mac.txt=t;
                rc_nget_w(rcfile,ml,t);
                t+=ml;
                *t++=M_END_MACRO;
                lg-=ml+1;
              }
              /*}}}  */
             while (lg>0);
             continue;
           }
          /*}}}  */
          /*{{{  macroinit/load*/
          case RC_LOADMACRO:
          case RC_INITMACRO:
           { int macro;
             int lg;
             off_t o;

             if (!fix_macros)
                goto rc_p_error;
             if (input==RC_LOADMACRO)
                o=ftell(rcfile);
             macro=rc_get_w(rcfile);
             if (macro>mac_count || macro<=0)
                goto rc_p_error;
             lg=rc_get_w(rcfile);
             if (input==RC_LOADMACRO)
              /*{{{  store demand info and skip code*/
              { demand_found=True;
                ((macro_entry*)fix_macros)[macro].mode=load;
                ((macro_entry*)fix_macros)[macro].mac.off=o;
                rc_skip_cw(rcfile,0,lg);
                ocl_msg("skip demand load %d",macro);
              }
              /*}}}  */
             else
              /*{{{  store function info and load*/
              { ((macro_entry*)fix_macros)[macro].mode=init;
                ((macro_entry*)fix_macros)[macro].mac.txt=paket_malloc((lg+1)*sizeof(TOKEN));
                if (!fix_macros[macro].mac.txt)
                   goto rc_mem_full;
                rc_nget_w(rcfile,lg,(int*)fix_macros[macro].mac.txt);
                ((TOKEN*)fix_macros[macro].mac.txt)[lg]=M_END_MACRO;
                ocl_msg("read macro %d",macro);
              }
              /*}}}  */
             continue;
           }
          /*}}}  */
          /*{{{  comment/os-extension*/
          case RC_OS_EXTENSION:
#            ifdef RC_OS_EXT_HANDLE
              /*{{{  special treatment*/
              { input=rc_get_c(rcfile);
                RC_OS_EXT_HANDLE(rcfile,input);
                continue;
              }
              /*}}}  */
#            endif
          case RC_COMMENT:
             rc_get_s(rcfile,(char*)0,INT_MAX);
             continue;
          /*}}}  */
          /*{{{  sets*/
          case RC_CHARSET:
             if (init_set())
                goto rc_p_error;
             ocl_msg("sets",0);
             continue;
          /*}}}  */
          /*{{{  marks*/
          case RC_MARKS:
           { char name[FOLD_PATTERN_LEN];

             /*{{{  read stored name*/
             rc_nget_c(rcfile,FOLD_PATTERN_LEN-1,name);
             name[FOLD_PATTERN_LEN-1]='\0';
             /*}}}  */
             if (mark_mode && !strcmp(mark_mode,name))
              /*{{{  reset mark strings*/
              { int i;

                mark_mode=0;
                for (i=4;i--;)
                   rc_nget_c(rcfile,FOLD_TAG_LENGTH,(char*)init_buffer.f.str.txt[i]);
                ocl_msg("read marks",0);
              }
              /*}}}  */
             else
              /*{{{  overread the data*/
              { rc_skip_cw(rcfile,4*FOLD_TAG_LENGTH,0);
                ocl_msg("skip marks",0);
              }
              /*}}}  */
             continue;
           }
          /*}}}  */
          /*{{{  mouse-tab*/
          case RC_M_TAB:
             mouse_number=rc_get_w(rcfile);
#            ifdef MOUSY
                if ((mouse_mapping=paket_malloc(mouse_number*sizeof(TOKEN)))==(TOKEN*)0)
                   goto rc_mem_full;
                rc_nget_w(rcfile,mouse_number,(int*)mouse_mapping);
#            else
                rc_skip_cw(rcfile,0,mouse_number);
#            endif
             ocl_msg("read mouse tab",0);
             continue;
          /*}}}  */
          /*{{{  reference compress words*/
          case RC_REF_COMP_STR:
             compofs=ftell(rcfile);
             ref_skip_comp_data(rcfile);
             continue;
          /*}}}  */
          /*{{{  error!*/
          default:
             goto rc_p_error;
          /*}}}  */
        }
       break;
     }
  }
  /*}}}  */
  /*{{{  store position for help!*/
  helpofs=ftell(rcfile);
  /*}}}  */
  /*{{{  malloc memory and copy user mode string*/
  { unsigned char *x;
    unsigned char **d;
    int i;

    if (u_m_p!=u_m_buff)
     /*{{{  copy buffer to malloced memory*/
     { if (!(x=paket_malloc(u_m_p-u_m_buff)))
        { rc_mem_full:
          eputs((unsigned char*)M_NO_MEMORY);
          eputc('\n');
          return(True);
        }
       memcpy(x,u_m_buff,u_m_p-u_m_buff);
     }
     /*}}}  */
    /*{{{  set char pointers and change comma*/
    for (i=2*MODE_COUNT-1,d=u_modes;i>=0;i--,d++)
       if (*d)
          *d=x+(*d-u_m_buff);
       else
          *d=(unsigned char*)empty_text;
    /*}}}  */
  }
  /*}}}  */
  /*{{{  mark mode missing*/
  if (mark_mode)
   { eputs((unsigned char*)M_FM);
     eputc('\n');
     return(True);
   }
  /*}}}  */
  /*{{{  if no macro-info or ktb given -> error*/
  if (!fix_macros || !kbd_read)
   { rc_p_error:

     if (!ocl_opt)
        eputs(get_msg(M_NO_KTAB,x));
     return(True);
   }
  /*}}}  */
  /*{{{  set standard-vars*/
  cy_ind= var_cur_lev;
  ocl_var[var_path].v=PATH_C;
  /*}}}  */
  if (!demand_found)
     rcclose();
  return(False);
}
/*}}}  */
/*{{{  load_demand*/
public TOKEN const *load_demand(int const n)
{
  ocl_msg("loading %d",n);
  if (n>=0 && n<=mac_count+1)
     switch (fix_macros[n].mode)
      { macro_entry m;
        int lg;

        case load:
           m=fix_macros[n];
           if
            /*{{{  use rcfile and seek to position*/
            (    (    rcfile
                   || (rcfile=fopen(open_sysfile(M_RCSTR,(char*)0),(char*)"rb"))
                 )
              && !fseek(rcfile,(off_t)m.mac.off,SEEK_SET)
              && rc_get_w(rcfile)==n
              && (lg=rc_get_w(rcfile))>=0
              && lg<OCL_CODE_LEN
            )
            /*}}}  */
            /*{{{  read and copy macro*/
            { char *s;

              if ((s=ori_malloc(sizeof(off_t)+(lg+1)*sizeof(TOKEN))))
               { m.mode=loaded;
                 *((off_t*)s)=m.mac.off;
                 m.mac.txt=(TOKEN*)(s+sizeof(off_t));
                 rc_nget_w(rcfile,lg,(int*)m.mac.txt);
                 ((TOKEN*)m.mac.txt)[lg]=M_END_MACRO;
                 lg=rc_get_c(rcfile);
                 if (lg<0 || lg>=RC_COUNT_TAGS)
                    paket_free(s);
                 else
                    ((macro_entry*)fix_macros)[n]=m;
               }
            }
            /*}}}  */
           if (m.mode==load)
              break;
        default:
           return(fix_macros[n].mac.txt);
      }

  warn_message(get_msg(F_DEMAND,n));

  return(0);
}
/*}}}  */
/*{{{  demand_unload*/
public void unload_demand(int const n)
{
  ocl_msg("unloading %d",n);
  if (n>=0 && n<=mac_count+1 && fix_macros[n].mode==loaded)
   { off_t *s;

     s=(off_t*)fix_macros[n].mac.txt;
     s-=1;
     ((macro_entry*)fix_macros)[n].mac.off= *s;
     ((macro_entry*)fix_macros)[n].mode=load;
     paket_free(s);
   }
  rcclose();
}
/*}}}  */
/*{{{  HostBegin*/
public void HostBegin(char *mark_mode)
{
  /*{{{  maybe get storage for memdump*/
#  ifdef NOMEMDUMP
     if (!(mem_dump_malloc=paket_malloc(NOMEMDUMP)))
      { eputs(M_NO_MEMORY);
        eputc('\n');
        goto init_failed;
      }
#  endif
  /*}}}  */
  /*{{{  get ori_path*/
  { char const *k;

    /*{{{  maybe overwrite path by environement*/
    if (ori_path==M_RC_PATH)
       if
        (    ((k=getenv(ORIPATH)) && k[0])
          || ((k=getenv(ORIPATH_1)) && k[0])
        )
          ori_path=k;
    if (!*ori_path)
     { ori_path_err:

       eputs((unsigned char*)M_INVALID_PATH);
       exit(r_arg_err);
     }
    /*}}}  */
    /*{{{  check, if correct defined path list, no double : or : at end of path!*/
    for (k=(char*)ori_path;;)
     { switch (*k++)
        { case '\0':
             break;
          case LIST_C:
          case LIST_C_1:
             switch (*k++)
              { case '\0':
                case LIST_C:
                case LIST_C_1:
                   goto ori_path_err;
                default:
                   continue;
              }
          default:
             continue;
        }
       break;
     }
    /*}}}  */
  }
  /*}}}  */
  /*{{{  open and check msg-file*/
  { char const *x;
    char name[_POSIX_PATH_MAX];

    x=open_sysfile(M_MSGSTR,name);
    if (!*x || (msg_file=open(x,O_RDONLY))<0)
     /*{{{  not there*/
     { eputs(get_msg(MSG_ARG_FORMAT,"%s %s\n",M_MIS_MES,name));
       goto init_failed;
     }
     /*}}}  */
    if (MSG_TEST_CHAR!=(char)*get_msg(T_TEST))
     /*{{{  bad data*/
     { char msg_found[MSG_LENGTH+1];

       strcpy(msg_found,(char*)get_msg(T_TEST));
       eputs
        ( get_msg
           ( MSG_ARG_FORMAT,
             M_IN_MES,
             T_TEST,
             MSG_TEST_CHAR,
             MSG_LENGTH,
             x,
             msg_found
           )
        );
       goto init_failed;
     }
     /*}}}  */
  }
  /*}}}  */
  /*{{{  get prompts.. from msg-file*/
  NO=get_msg(I_NO)[0];
  YES=get_msg(I_YES)[0];
  AB=get_msg(I_AB)[0];
  DO_AB=get_msg(I_DO_AB)[0];
  DO_REST=get_msg(I_DO_REST)[0];
  /*}}}  */
  /*{{{  parse rc-file*/
  if (rcfileparser((char*)0,mark_mode))
     goto init_failed;
  /*}}}  */
  /*{{{  init keyboard and screen*/
  if (get_terminal_capability())
     goto init_failed;
  init_keyboard();
  init_signals();
  init_terminal();
  allow_text_so=(so && !sg);
  chg_dsp_type('c');
  /*}}}  */
  return;

init_failed:
  exit(r_init_err);
}
/*}}}  */
/*{{{  initialise links in editor*/
public void initialise(void)
{
  new_data(&null_element);
  set_linetyp(null_element,NOT_FOLD);
  null_element.indent = 0;
  null_element.x.fold.UU.U1.indent = 0;
  null_element.x.fold.data = 0;
  null_element.x.fold.UU.U1.type = DEFAULT_TYPE;
  null_element.x.fold.UU.U1.contents = TEXT_CONTENTS;
  null_element.x.fold.close_line = DEF_CURSOR_LINE;
  pick_head=proc_new_element();
  pick_tail = pick_head;
}
/*}}}  */
