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

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

#define ORIEDT_C
#define I_BUFFLOOP_C
#define I_DISPLAY_C
#define I_FINDS_C
#define I_FOLDHELP_C
#define I_FOLDING_C
#define I_GETMSG_C
#define I_GETTK_C
#define I_LOOP_C
#define I_MAIN_C
#define I_MISC_C
#define I_MESSAGES_C
#define I_PROMPT_C
#define I_SCREEN_C
#define I_SIGNALS_C
#define I_STRING_C
#define I_VIRTUAL_C

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


/*{{{  size of element-blocks*/
#ifdef VIRTUAL
#  define NEW_ELEMENT_START (vir_nodes?NEW_ELEMENT_MAX:NEW_ELEMENT_LIMIT)
#else
#  define NEW_ELEMENT_START NEW_ELEMENT_LIMIT
#endif
/*}}}  */
/*{{{  variables*/
private element *dispose_tail = &null_element;
#define dispose_head (&null_element)
private boolean warn_mem=True;
/*}}}  */

/*{{{  flat_dispose_list*/
private void flat_dispose_list(boolean all)
{

#ifdef VIRTUAL
  if (!vir_nodes)
#endif
   { element *p;

     for (p=dispose_head;p!=dispose_tail;)
      { p=p->next;
        set_0_data(p);
        if (test_linetyp(*p,(START_FOLD|START_FILED)))
         { element *q;

           q = p->x.fold.other_end;
           set_linetyp(*p,NOT_FOLD);
           set_linetyp(*q,NOT_FOLD);
           if (dispose_tail == p)
              dispose_tail = q;
           p->next = p->x.fold.data;
         }
        if (!all)
           break;
     }
   }
}
/*}}}  */
/*{{{  ori_malloc*/
public void *ori_malloc(size_t length)
{ void *x;

  if (!(x=paket_malloc(length)))
   { flat_dispose_list(True);
     if (!(x=paket_malloc(length)))
      { shrink_history();
        if (!(x=paket_malloc(length)))
         {
           /*{{{  maybe warn*/
           if (warn_mem)
              warn_message(M_NO_MALLOC);
           warn_mem=True;
           /*}}}  */
           /*{{{  clear delete buffers*/
           { int i;
             element **d;

             for (i=0,d=deleted_lines;i<UNDEL_LINES;i++,d++)
                if (*d)
                 { proc_dispose(*d);
                   *d=0;
                 }
           }
           delete_ptr=0;
           /*}}}  */
           flat_dispose_list(True);
           x=paket_malloc(length);
           if (!x)
              ori_abort(~SIGINT);
         }
      }
   }
  return(x);
}
/*}}}  */
/*{{{  spaces                fill a string with spaces*/
public void spaces(unsigned char *s, int l)
{
  for (;l>0;)
   { l--;
     *s++=' ';
   }
  *s=0;
}
/*}}}  */
/*{{{  trailing_spaces*/
public void trailing_spaces(unsigned char *s)
{
  unsigned char *y=s;

  for (;;)
   { switch (*s++)
      { default:
           y=s;
        case ' ':
        case '\t':
           continue;
        case '\0':;
      }
     break;
   }
  *y='\0';
}
/*}}}  */
/*{{{  join_links*/
public void join_links(element * const p,element * const q)
{
  p->next = q;
  q->prec = p;
  if (test_linetyp(*p,START_FOLD|START_FILED))
     p->x.fold.other_end->next = q;
}
/*}}}  */
/*{{{  move_on*/
public element *move_on(element const *p)
{
  if (test_linetyp(*p,START_FOLD))
     p=p->x.fold.data;
  else
     p=p->next;

  return((element*)p);
}
/*}}}  */
/*{{{  close_fold_at*/
public void close_fold_at(element * const ptr)
{
  element *p;
  int i;

  p = ptr;
  /*{{{  start fold ?*/
  if (test_linetyp(*p,START_OPEN_FOLD))
   { set_linetyp(*p,START_FOLD);
     p->x.fold.data = p->next;
     p->next = p->x.fold.other_end->next;
     p->next->prec = p;
   }
  /*}}}  */
  i = p->x.fold.UU.U1.indent;
  p->indent -= i;
  i += p->indent;
  p = p->x.fold.data;
  /*{{{  search matching end-fold*/
  for (;;)
   { switch (get_linetyp(*p))
      { case END_FOLD:
           break;
        case START_OPEN_FOLD:
           close_fold_at(p);
        default:
           p->indent -= i;
           p = p->next;
           continue;
      }
     break;
   }
  /*}}}  */
  p->indent -= i;
}
/*}}}  */
/*{{{  proc_dispose*/
public void proc_dispose(element * const p)
{
  join_links(dispose_tail, p);
  dispose_tail = p;
}
/*}}}  */
/*{{{  proc_new_element*/
public element *proc_new_element(void)
{
  element *n;

  if (dispose_head == dispose_tail)
   /*{{{  malloc new space*/
   { static element base_element[BASIC_ELEMENTS];
     static element *el_ptr=base_element;
     static int el_used=BASIC_ELEMENTS;

     if (!el_used)
      /*{{{  malloc a new big element's-block*/
      { el_used=NEW_ELEMENT_START;
        el_ptr=0;
        while (el_used && !(el_ptr=ori_malloc(el_used*sizeof(element))))
         { if (dispose_head != dispose_tail)
            { el_used=0;
              goto del_list_usage;
            }
           el_used=el_used>>1;
           warn_mem=False;
         }
        warn_mem=True;
        if (!el_used)
           exit_origami(r_mem_full,M_NO_MEMORY);
      }
      /*}}}  */
     /*{{{  use element in allocated block*/
     n=el_ptr++;
     el_used--;
     /*}}}  */
   }
   /*}}}  */
  else
   /*{{{  use node from list*/
   { del_list_usage:
     flat_dispose_list(False);
     n = dispose_head->next;
     /*{{{  join correct links for dispose-list*/
     if (dispose_tail == n)
        dispose_tail = dispose_head;
     else
        join_links(dispose_head, n->next);
     /*}}}  */
   }
   /*}}}  */
  /*{{{  init data of new element*/
  *n = null_element;
  /*}}}  */
  return(n);
}
/*}}}  */
/*{{{  set_fold_mark_dsp_length*/
public void set_fold_mark_dsp_length(struct f_m_str * const fm)
{
  int i;

  for (fm->o_dsp_l=fm->l_dsp_l=2*dsp.norm,i=FOLD_TAG_LENGTH-1;i>=0;i--)
   { fm->o_dsp_l+=char_dsp_size(fm->open_f[i]);
     fm->l_dsp_l+=char_dsp_size(fm->line_f[i]);
   }
}
/*}}}  */
/*{{{  proc_to_edit_pos*/
public void proc_to_edit_pos(void)
{
  int x;

  x=bd.f.current->indent*dsp.norm;
  switch(get_linetyp(*bd.f.current))
   { case START_FOLD:
     case START_FILED:
        bd.e.pre_scr_e_pos=x+bd.f.current->x.fold.UU.U1.indent*dsp.norm+1;
        bd.e.first_scr_e_pos=bd.e.pre_scr_e_pos+bd.f.str.l_dsp_l;
        break;
     case START_OPEN_FOLD:
     case START_ENTER_FOLD:
        bd.e.pre_scr_e_pos=0;
        bd.e.first_scr_e_pos=x+1+bd.f.str.o_dsp_l;
        break;
     case END_FOLD:
     case START_ENTER_FILED:
        bd.e.pre_scr_e_pos=0;
        bd.e.first_scr_e_pos=LINELEN+1;
        break;
     default:
        bd.e.pre_scr_e_pos=x-dsp.norm+1;
        bd.e.first_scr_e_pos=x+1;
        break;
   }
}
/*}}}  */
/*{{{  proc_from_edit_pos*/
public void proc_from_edit_pos(void)
{
  if (test_linetyp(*bd.f.current,(START_FOLD|START_FILED)))
   { int i;

     /*{{{  i=number of leading spaces*/
     { unsigned char *l;

       for (i=0,l=cur_dsp_line;*l==' ';l++,i++);
     }
     /*}}}  */
     bd.f.current->x.fold.UU.U1.indent=i-bd.f.current->indent;
   }
}
/*}}}  */
/*{{{  copyin*/
public void copyin
 ( unsigned char * const line,
   const element * const p,
   const boolean full
 )
{
  /*{{{  variables*/
  const unsigned char *mark_ptr;
  const unsigned char *gap_ptr;
  unsigned char *l_ptr;
  int ind;
  linetyp lt;
  unsigned char *lp;
  /*}}}  */

  /*{{{  get data for line*/
  if ((lt=get_linetyp(*p))&END_FOLD)
     if (no_fold_out)
      { *line=0;
        return;
      }
     else
        l_ptr=(unsigned char*)empty_text;
  else
     l_ptr=get_data(p);
  ind = p->indent;
  /*}}}  */
  /*{{{  handle line-typ*/
  switch (lt)
   {
     /*{{{  filed or fold*/
     case START_FOLD:
     case START_FILED:
        if (no_fold_out)
         { mark_ptr=pseudo_mark;
           gap_ptr=two_space;
         }
        else
         { mark_ptr=full?bd.f.str.open_f:bd.f.str.line_f;
           gap_ptr=(lt&START_FILED)?fold_f:two_space;
         }
        ind += p->x.fold.UU.U1.indent;
        break;
     /*}}}  */
     /*{{{  begin fold*/
     case START_OPEN_FOLD:
     case START_ENTER_FOLD:
        if (no_fold_out)
           mark_ptr=pseudo_mark;
        else
           mark_ptr=bd.f.str.open_f;
        gap_ptr=two_space;
        break;
     /*}}}  */
     /*{{{  start enter filed*/
     case START_ENTER_FILED:
        if (no_fold_out)
         { mark_ptr=pseudo_mark;
           gap_ptr=two_space;
         }
        else
         { ind=0;
           mark_ptr=bd.f.str.open_f;
           gap_ptr=fold_f;
         }
        break;
     /*}}}  */
     /*{{{  end fold*/
     case END_FOLD:
        mark_ptr=bd.f.str.close_f;
        gap_ptr=(full && dialects[bd.m.dialect.typ].txt.end[0])?two_space:0;
        break;
     /*}}}  */
     /*{{{  text*/
     case NOT_FOLD:
        mark_ptr=0;
        break;
     /*}}}  */
     default:
        exit_origami(exit_failure,get_msg(F_INT_OCL,STR_INV_FOLD,lt));
   }
  /*}}}  */
  /*{{{  gen indentation spaces, set lp to text-start*/
  for (lp=line;ind>0;ind--)
     *lp++=' ';
  /*}}}  */
  if (mark_ptr)
   /*{{{  append leading-fold-mark/text/trailing-fold-mark*/
   {
     /*{{{  leading comment*/
     if (full)
      { ustrcpy(lp,dialects[bd.m.dialect.typ].txt.start);
        lp+=dialects[bd.m.dialect.typ].lg.start;
      }
     /*}}}  */
     /*{{{  mark*/
     ustrcpy(lp,mark_ptr);
     lp+=FOLD_TAG_LENGTH;
     /*}}}  */
     /*{{{  gap*/
     if (gap_ptr)
      { ustrcpy(lp,gap_ptr);
        lp+=2;
      }
     /*}}}  */
     /*{{{  text*/
     ustrcpy(lp,l_ptr);
     /*}}}  */
     /*{{{  trailing comment*/
     if (full)
        ustrcat(lp,dialects[bd.m.dialect.typ].txt.end);
     /*}}}  */
   }
   /*}}}  */
  else
   /*{{{  append only text*/
     ustrcpy(lp,l_ptr);
   /*}}}  */
  if (full && ind)
     trailing_spaces(line);
}
/*}}}  */
/*{{{  copyout*/
public void copyout(unsigned char const * const line,element * const p)
{
  int i;
  linetyp lt;

  i=p->indent;
  if (!((lt=get_linetyp(*p))&NOT_FOLD))
     i+=FOLD_TAG_LENGTH+2;
  if (lt&(START_FOLD|START_FILED))
     i+=p->x.fold.UU.U1.indent;
  set_data(p,strsub(line,i+1),lt&NOT_FOLD);
}
/*}}}  */
