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

#include <sys/types.h>
#ifndef NO_MAIL
#  ifndef USEGETHOSTNAME
#     include <sys/utsname.h>
#  else
#     define utsname { char nodename[1024]; }
#     define uname(x) gethostname(&((x)->nodename),1023)
#  endif
#endif
#include <pwd.h>
#include <unistd.h>
#include <limits.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define LOOP_C
#define I_BUFFLOOP_C
#define I_DISPLAY_C
#define I_FOLDFILING_C
#define I_FOLDHELP_C
#define I_FOLDING_C
#define I_FINDS_C
#define I_GETMSG_C
#define I_GETTK_C
#define I_KEYBOARD_C
#define I_MAIN_C
#define I_MISC_C
#define I_MESSAGES_C
#define I_ORIEDT_C
#define I_PROMPT_C
#define I_READFOLDS_C
#define I_SCREEN_C
#define I_SIGNALS_C
#define I_VIRTUAL_C

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

/*{{{  variables*/
public unsigned char line_buffer[LINELEN + 1];
public FILE *start_pipe=0;
public boolean running=False;
public buffer_data init_buffer=
 {
   /*{{{  screen data*/
   { 0,      /* no */
     0,      /* id */
     /*{{{  off set*/
     { 0,    /* w */
       0     /* h */
     },
     /*}}}  */
     /*{{{  win dow size*/
     { 0,    /* w */
       0     /* h */
     },
     /*}}}  */
     True,   /* clreol */
     True,   /* bold_stat */
     /*{{{  txt_size*/
     { 0,    /* w */
       0     /* h */
     },
     /*}}}  */
     0,      /* start */
     0,      /* end */
     /*{{{  cursor positions*/
     { 0,    /* w */
       0     /* h */
     },
     /*}}}  */
     1,      /* shift_w_size */
     0,      /* shift_w_offset */
     0,      /* screen_shift_w_offset */
     1       /* end_level */
#   ifdef MULTIPLE_SCREEN
        MULT_SCR_INIT
#   endif
   },
   /*}}}  */
   /*{{{  fold data*/
   { { { END_STANDARD, FILE_STANDARD, LINE_STANDARD, BEGIN_STANDARD },
       FOLD_TAG_LENGTH,
       FOLD_TAG_LENGTH,
     },      /* fold marks */
     False,  /* count_comment_line */
     0,      /* entered */
     0,      /* enter_spaces */
     0,      /* real_head */
     0,      /* real_tail */
     0,      /* head */
     0,      /* tail */
     0,      /* End_of_fold */
     0,      /* Start_of_fold */
     0,      /* Line_after_fold */
     0,      /* current */
     NOT_FOLD,
             /* cur_line_typ */
     0       /* select_ptr */
   },
   /*}}}  */
   /*{{{  editing*/
   { 0,      /* first_edit_pos */
     0,      /* pre_edit_pos */
     0,      /* part_line */
     False,  /* split_line */
     False,  /* fold_in */
     0,      /* file_no */
     0,      /* makefold_indent */
   },
   /*}}}  */
   /*{{{  mode data*/
   { no_selection,
     True,   /* last display used not selection */
     False,  /* select_mode */
     False,  /* full_shift */
     False,  /* hash_shift */
     False,  /* overwrite */
     False,  /* read_only */
     False,  /* user_view */
     unchanged_file,
             /* file_changed_status */
     False,  /* dir_edit */
     { F_C_NONE,   /* dialect */
       { 0,0 },
             /* length of comments */
       "","" /* empty texts */
     }
   },
   /*}}}  */
   /*{{{  screen modes*/
   { 0,    /* last x position */
     0     /* y position */
   }
   /*}}}  */
 };
public win_data root_dont_use={ 0,0 };
public boolean no_fold_out=False;
public int startup_line=0;
private int buff_id_used=1;
/*}}}  */

/*{{{  buffer data*/
private int curr_buff;
private int bd_buffer;
private int dsp_buff;
public int buff_used;

public int mult_edit;

#define B_L_PAKET 8
private buffer_data **buffer_list;
int b_l_size;

public buffer_data bd;
/*}}}  */
/*{{{  warn_mult_edit*/
public void warn_mult_edit(void)
{ int search,i,n;

  for
   ( n=0,
     i=buff_used-1,
     search=(bd_buffer==curr_buff)
             ? bd.e.file_no
             : buffer_list[curr_buff]->e.file_no
   ; i>=0
   ; i--
   )
     if (i!=curr_buff && buffer_list[i]->e.file_no==search)
        n++;
  ocl_var[var_m_edit].v=(mult_edit=n)+1;
}
/*}}}  */
/*{{{  set_bd*/
private void set_bd(buffer_data const * const b)
{
  bd= *b;
  dialects[F_C_USER].lg=bd.m.dialect.lg;
}
/*}}}  */
/*{{{  save_bd*/
private void save_bd(buffer_data * const b)
{
  bd.m.dialect.lg=dialects[F_C_USER].lg;
  *b=bd;
}
/*}}}  */
/*{{{  window handling*/
/*{{{  constants*/
#define min_scr_height (TXT_MIN_H-var_notitle)
#define min_scr_width  TXT_MIN_W
/*}}}  */
/*{{{  typdef w_op*/
typedef enum
 { resize,
   del,
   h_grow,h_shrink,h_splitt,h_t_splitt,
   w_grow,w_shrink,w_splitt,w_l_splitt
 } w_op;
/*}}}  */
#ifndef MULTIPLE_SCREEN
  /*{{{  type w_type*/
  typedef enum { single,top_down,left_right } w_type;
  /*}}}  */
  /*{{{  type window*/
  typedef struct window
   { win_data s;
     win_data saved_s;
     w_type t;
     union
      { struct { struct window *w1;struct window *w2; } node;
        struct { buffer_data const *b; } edge;
      } dat;
   } window;
  /*}}}  */
  /*{{{  variables*/
  private win_data splitt;
  private win_data root_size;
  private win_data min_cur_size;
  private w_op rec_win_op;
  private buffer_data const *win_buff_arg;
  private window *root_window;
  /*}}}  */

  /*{{{  init_root_window_size*/
  private void init_root_window_size(void)
  {
    if ((message_line=screen.h-root_dont_use.h)<=0)
       message_line=1;
    area_line.h=message_line-area_used;
    if (area_line.h<=min_scr_height)
       area_line.h=message_line-1;
    if (area_line.h<=0)
       area_line.h=1;
    if ((area_line.w=root_size.w=screen.w-root_dont_use.w)<=0)
       area_line.w=1;
    if ((root_size.h=(area_used?area_line.h:message_line)-1)<=0)
       root_size.h=1;
  }
  /*}}}  */
  /*{{{  window_op*/
  /*{{{  variables*/
  private win_data add_from_delete;
  /*}}}  */

  /*{{{  rec_w_op*/
  private win_data rec_w_op(window*w,win_data s,boolean hs,boolean ws)
  {
    switch (w->t)
     {
       /*{{{  single node=1 window*/
       case single:
          if (w->dat.edge.b==buffer_list[curr_buff])
           { s=w->s;
             /*{{{  handle op*/
             switch(rec_win_op)
              { case h_splitt:
                case h_t_splitt:
                case w_splitt:
                case w_l_splitt:
                 { window *n_tl_win,*n_br_win;

                   /*{{{  get new edge's*/
                   if
                    (    !(n_tl_win=ori_malloc(sizeof(window)))
                      || !(n_br_win=ori_malloc(sizeof(window)))
                    )
                      exit_origami(r_mem_full,M_NO_MEMORY);
                   /*}}}  */
                   /*{{{  init some edge data*/
                   *n_tl_win = *w;
                   n_br_win->t=single;
                   n_br_win->dat.edge.b=win_buff_arg;
                   /*}}}  */
                   if (rec_win_op==h_splitt || rec_win_op==h_t_splitt)
                    { splitt.h++;
                      /*{{{  set nodes*/
                      w->t=top_down;
                      if (rec_win_op==h_splitt)
                       { w->dat.node.w1=n_tl_win;
                         w->dat.node.w2=n_br_win;
                       }
                      else
                       { w->dat.node.w1=n_br_win;
                         w->dat.node.w2=n_tl_win;
                       }
                      /*}}}  */
                      /*{{{  set sizes*/
                      n_br_win->saved_s.w=n_br_win->saved_s.h=0;
                      n_br_win->s.w=n_tl_win->s.w;
                      n_tl_win->s.h/=2;
                      n_br_win->s.h=w->s.h-n_tl_win->s.h;
                      /*}}}  */
                      ori_assert(w->s.h==s.h && w->s.w==s.w,"single size splitt top diff in regop");
                      ori_assert(w->s.w==w->dat.node.w1->s.w && w->s.w==w->dat.node.w2->s.w,"single size splitt width diff in regop");
                      ori_assert(w->s.h==w->dat.node.w1->s.h+w->dat.node.w2->s.h,"single size splitt height-sum diff in regop");
                    }
                   else
                    { splitt.w++;
                      /*{{{  set nodes*/
                      w->t=left_right;
                      if (rec_win_op==w_splitt)
                       { w->dat.node.w1=n_tl_win;
                         w->dat.node.w2=n_br_win;
                       }
                      else
                       { w->dat.node.w1=n_br_win;
                         w->dat.node.w2=n_tl_win;
                       }
                      /*}}}  */
                      /*{{{  set sizes*/
                      n_br_win->saved_s.w=n_br_win->saved_s.h=0;
                      n_br_win->s.h=n_tl_win->s.h;
                      n_tl_win->s.w/=2;
                      n_br_win->s.w=w->s.w-n_tl_win->s.w;
                      /*}}}  */
                      ori_assert(w->s.w==s.w && w->s.h==s.h,"single size splitt top diff in regop");
                      ori_assert(w->s.h==w->dat.node.w1->s.h && w->s.h==w->dat.node.w2->s.h,"single size splitt height diff in regop");
                      ori_assert(w->s.w==w->dat.node.w1->s.w+w->dat.node.w2->s.w,"single size splitt width-sum diff in regop");
                    }
                   break;
                 }
                case h_grow:  s.h++;break;
                case h_shrink:s.h--;break;
                case w_grow:  s.w++;break;
                case w_shrink:s.w--;break;
                case del:     break;
                /*{{{  resize, maybe add deleted size*/
                case resize:
                   s.h+=add_from_delete.h;
                   add_from_delete.h=0;
                   s.w+=add_from_delete.w;
                   add_from_delete.w=0;
                   break;
                /*}}}  */
              }
             if (rec_win_op!=del)
                rec_win_op=resize;
             /*}}}  */
             ori_assert(rec_win_op!=del || w->dat.edge.b!=win_buff_arg,"del in single node");
             /*{{{  handle height*/
             if (s.h>root_size.h)
                s.h=root_size.h;
             else if (s.h<min_cur_size.h)
                s.h=min_cur_size.h;
             if (!hs && s.h<root_size.h)
                s.h=root_size.h;
             /*}}}  */
             /*{{{  handle width*/
             if (s.w>root_size.w)
                s.w=root_size.w;
             else if (s.w<min_cur_size.w)
                s.w=min_cur_size.w;
             if (!ws && s.w<root_size.w)
                s.w=root_size.w;
             /*}}}  */
           }
          w->s=s;
          ori_assert(w->s.h==s.h && w->s.w==s.w,"single size diff in regop");
          break;
       /*}}}  */
       /*{{{  top-down/left_right*/
       case top_down:
       case left_right:
        { window *w1,*w2;

          w1=w->dat.node.w1;
          w2=w->dat.node.w2;
          if (rec_win_op==del)
           /*{{{  maybe delete the current node from window tree*/
           { if (w1->t==single && w1->dat.edge.b==win_buff_arg)
              /*{{{  change bottom/right and top/left*/
              { w2=w1;
                w1=w->dat.node.w2;
              }
              /*}}}  */
             if (w2->t==single && w2->dat.edge.b==win_buff_arg)
              /*{{{  delete bottom/right node*/
              {
                /*{{{  store deleted size*/
                if (w->t==top_down)
                   add_from_delete.h=w2->s.h;
                else
                   add_from_delete.w=w2->s.w;
                /*}}}  */
                /*{{{  handle number of splitts*/
                if (w->t==top_down)
                   splitt.h--;
                else
                   splitt.w--;
                /*}}}  */
                /*{{{  delete node*/
                *w = *w1;
                paket_free(w1);
                paket_free(w2);
                /*}}}  */
                /*{{{  return resized data*/
                win_buff_arg=0;
                rec_win_op=resize;
                s=rec_w_op(w,s,hs,ws);
                break;
                /*}}}  */
              }
              /*}}}  */
           }
           /*}}}  */
          /*{{{  handle both parts of the window tree*/
          { win_data s1,s1n,s2,s2n;
            boolean first_current;

            for (;;)
             { s1=w1->s;
               s2=w2->s;
               if (w->t==top_down)
                /*{{{  handle top_down*/
                {
                  /*{{{  handle top node*/
                  s1n.w=s.w;
                  s1n.h=  ((s1.h+s2.h)==s.h)
                        ? s1.h
                        : (s.h*(s1.h+1))/(s1.h+s2.h+2);
                  s1=rec_w_op(w1,s1n,True,ws);
                  ori_assert(s1.h==w1->s.h,"top-down-heights1 diff in recop");
                  ori_assert(s1.w==w1->s.w,"top-down-widths1 diff in recop");
                  first_current= !(s1.h==s1n.h && s1.w==s1n.w);
                  /*}}}  */
                  /*{{{  handle bottom*/
                  s2n.w=s1.w;
                  if (s1.h==s1n.h)
                     s2n.h=s.h-s1n.h;
                  else if (s1.h==root_size.h)
                     s2n.h=0;
                  else if (s1.h>=s.h)
                   { s2n.h=root_size.h-s1.h;
                     if (hs) s2n.h/=2;
                   }
                  else
                     s2n.h=s.h-s1.h;
                  s2=rec_w_op(w2,s2n,True,ws);
                  ori_assert(s2.h==w2->s.h,"top-down-heights2 diff in recop");
                  ori_assert(s2.w==w2->s.w,"top-down-widths2 diff in recop");
                  /*}}}  */
                  if (s1.w==s2.w && s1.h+s2.h==s.h)
                   /*{{{  this size is ok, so return*/
                   { s.w=s1.w;
                     s.h=s1.h+s2.h;
                     w->s=s;
                     ori_assert(w->s.w==w1->s.w && w->s.w==w2->s.w,"left-right-widths diff in ret-rec-op");
                     ori_assert(w->s.h==w1->s.h+w2->s.h,"left-right-height-sum diff in ret-rec-op");
                     break;
                   }
                   /*}}}  */
                  /*{{{  get new target size for both windows*/
                  if (w==root_window)
                     s=root_size;
                  else
                   { s.w=first_current?s1.w:s2.w;
                     if (hs)
                      { s.h=first_current?s1.h:s2.h;
                        s.h+=(root_size.h-s.h)/2;
                      }
                     else
                        s.h=root_size.h;
                   }
                  w->s=s;
                  /*}}}  */
                  /*{{{  set new top side*/
                  s1n.w=s2.w;
                  s1n.h=s.h-s2.h;
                  /*}}}  */
                }
                /*}}}  */
               else
                /*{{{  handle left_right*/
                {
                  /*{{{  handle left*/
                  s1n.h=s.h;
                  s1n.w=  ((s1.w+s2.w)==s.w)
                        ? s1.w
                        : (s.w*(s1.w+1))/(s1.w+s2.w+2);
                  s1=rec_w_op(w1,s1n,hs,True);
                  ori_assert(s1.h==w1->s.h,"left-right-heights1 diff in recop");
                  ori_assert(s1.w==w1->s.w,"left-right-widths1 diff in recop");
                  first_current= !(s1.h==s1n.h && s1.w==s1n.w);
                  /*}}}  */
                  /*{{{  handle right*/
                  s2n.h=s1.h;
                  if (s1.w==s1n.w)
                     s2n.w=s.w-s1.w;
                  else if (s1.w==root_size.w)
                     s2n.w=0;
                  else if (s1.w>=s.w)
                   { s2n.w=root_size.w-s1.w;
                     if (ws) s2n.w/=2;
                   }
                  else
                     s2n.w=s.w-s1.w;
                  s2=rec_w_op(w2,s2n,hs,True);
                  ori_assert(s1.h==w1->s.h,"left-right-heights2 diff in recop");
                  ori_assert(s1.w==w1->s.w,"left-right-widths2 diff in recop");
                  /*}}}  */
                  if (s1.h==s2.h && s1.w+s2.w==s.w)
                   /*{{{  this size is ok, so return*/
                   { s.h=s1.h;
                     s.w=s1.w+s2.w;
                     w->s=s;
                     ori_assert(w->s.h==w1->s.h && w->s.h==w2->s.h,"left-right-heights diff in ret-rec-op");
                     ori_assert(w->s.w==w1->s.w+w2->s.w,"left-right-width-sum diff in ret-rec-op");
                     break;
                   }
                   /*}}}  */
                  /*{{{  get new target size for both windows*/
                  if (w==root_window)
                     s=root_size;
                  else
                   { s.h=first_current?s1.h:s2.h;
                     if (ws)
                      { s.w=first_current?s1.w:s2.w;
                        s.w+=(root_size.w-s.w)/2;
                      }
                     else
                        s.w=root_size.w;
                   }
                  w->s=s;
                  /*}}}  */
                  /*{{{  set new left side*/
                  s1n.h=s2.h;
                  s1n.w=s.w-s2.w;
                  /*}}}  */
                }
                /*}}}  */
               s1n=rec_w_op(w1,s1n,hs,True);
               ori_assert(s1n.h==w1->s.h && s1n.w==w1->s.w,"inner node second-first failed");
               break;
             }
          }
          /*}}}  */
          break;
        }
       /*}}}  */
     }
    ori_assert(w->s.h==s.h && w->s.w==s.w,"recop failed");
    return(s);
  }
  /*}}}  */
  /*{{{  rec_scr2buff*/
  private void rec_scr2buff(window *w,win_data o)
   {
     if (w->t==single)
      /*{{{  set window data to buff*/
      { buffer_data *b;

        b=(buffer_data*)w->dat.edge.b;
        b->scr.win=b->scr.txt_size=w->s;
        if (!var_notitle) b->scr.txt_size.h-=1;
        b->scr.off=o;
        b->scr.clreol=((b->scr.win.w+b->scr.off.w+root_dont_use.w)==screen.w);
        b->scr.bold_stat=(boolean)so;
        if (sg && b->scr.win.w<=2*sg+MIN_SG_TITLE)
           b->scr.bold_stat=False;
      }
      /*}}}  */
     else
      /*{{{  handle inner node*/
      { rec_scr2buff(w->dat.node.w1,o);
        if (w->t==top_down)
           o.h+=w->dat.node.w1->s.h;
        else
           o.w+=w->dat.node.w1->s.w;
        rec_scr2buff(w->dat.node.w2,o);
      }
      /*}}}  */
   }
  /*}}}  */

  private boolean window_op(w_op o,buffer_data const * /*const*/ b)
  {
    /*{{{  handle error situations*/
    switch (o)
     {
       /*{{{  h_[t_]splitt maybe use full height*/
       case h_splitt:
       case h_t_splitt:
          if (root_dont_use.h)
           /*{{{  use full height!*/
           { root_dont_use.h=0;
             init_root_window_size();
             window_op(resize,(buffer_data*)0);
           }
           /*}}}  */
          break;
       /*}}}  */
       /*{{{  h_grow       check if possible, maybe dec don't use*/
       case h_grow:
          if (splitt.h)
             break;
          if (!root_dont_use.h)
             return(True);
          root_dont_use.h-=1;
          init_root_window_size();
       dont_use_change:
        { int i;

          for (i=0;scr_off;ocl_screen_on(),i++);
          ClrScr();
          for (;i;ocl_screen_off(),i--);
          break;
        }
       /*}}}  */
       /*{{{  h_shrink     check if possible, maybe inc don't use*/
       case h_shrink:
          if (splitt.h)
             break;
          if (root_dont_use.h+min_scr_height>=screen.h)
             return(True);
          root_dont_use.h++;
          init_root_window_size();
          goto dont_use_change;
       /*}}}  */
       /*{{{  w_[l_]splitt maybe use full width*/
       case w_splitt:
       case w_l_splitt:
          if (root_dont_use.w)
           /*{{{  use full width!*/
           { root_dont_use.w=0;
             init_root_window_size();
             window_op(resize,(buffer_data*)0);
           }
           /*}}}  */
          break;
       /*}}}  */
       /*{{{  w_grow       check if possible, maybe dec don't use'*/
       case w_grow:
          if (splitt.w) break;
          if (!root_dont_use.w) return(True);
          root_dont_use.w--;
          init_root_window_size();
          goto dont_use_change;
       /*}}}  */
       /*{{{  w_shrink     check if possible, maybe inc don't use'*/
       case w_shrink:
          if (splitt.w) break;
          if (root_dont_use.w+min_scr_width>=screen.w) return(True);
          root_dont_use.w++;
          init_root_window_size();
          goto dont_use_change;
       /*}}}  */
       /*{{{  del          check if possible*/
       case del:
          if (splitt.w==0 && splitt.h==0)
             return(True);
          else
             break;
       /*}}}  */
       default:
          break;
     }
    /*}}}  */
    /*{{{  set minimum size*/
    min_cur_size.h=((min_scr_height<root_size.h)?min_scr_height:root_size.h);
    min_cur_size.w=((min_scr_width <root_size.w)?min_scr_width :root_size.w);
    /*}}}  */
    /*{{{  do the window operation*/
    for
     ( rec_win_op=o,
       win_buff_arg=b,
       add_from_delete.h=add_from_delete.w=0
     ;
     ; o=resize,
       b=0
     )
     { rec_w_op(root_window,root_size,False,False);
       if (add_from_delete.h==0 && add_from_delete.w==0)
          break;
     }
    /*}}}  */
    /*{{{  store window data in buffers*/
    { win_data off;

      off.h=off.w=0;
      rec_scr2buff(root_window,off);
    }
    /*}}}  */

    return(False);
  }
  /*}}}  */
  /*{{{  win_layout*/
  /*{{{  rec_win_layout*/
  private boolean rec_win_layout(window * const w,boolean restore)
  {
    switch (w->t)
     {
       case top_down:
       case left_right:
          rec_win_layout(w->dat.node.w1,restore);
          rec_win_layout(w->dat.node.w2,restore);
       case single:
          if (restore)
             w->s=w->saved_s;
          else
             w->saved_s=w->s;
          break;
     }
    return(restore);
  }
  /*}}}  */
#  define win_layout(t) rec_win_layout(root_window,t)
  /*}}}  */
  /*{{{  init_window*/
  private void init_window(buffer_data const * const b)
  {
    init_root_window_size();
    init_buffer.scr.off.h=0;
    init_buffer.scr.off.w=0;
    splitt.h=splitt.w=0;
    if (!(root_window=paket_malloc(sizeof(window))))
       exit_origami(r_mem_full,M_NO_MEMORY);
    root_window->t=single;
    root_window->s=root_size;
    root_window->dat.edge.b=b;
  }
  /*}}}  */
#endif
/*{{{  calc_window*/
private void set_shift_size(void);
#define calc_window() (window_op(resize,(buffer_data*)0),set_shift_size())
/*}}}  */
/*{{{  go_window*/
private boolean go_window(int const no)
{
  if (no<0 || no>=buff_used)
     return(True);

  curr_buff=no;
  warn_mult_edit();
  call_number_macro(buff_macro);

  return(False);
}
/*}}}  */
/*{{{  splitt_window*/
private void splitt_window
 ( boolean const t_d,
   boolean const rev,
   int const old,
   buffer_data const * const b)
{ int c;

  c=curr_buff;
  curr_buff=old;
  window_op
   ( rev
      ? (t_d?h_t_splitt:w_l_splitt)
      : (t_d?h_splitt:w_splitt),
     b
   );
  curr_buff=c;
}
/*}}}  */
/*{{{  del_window*/
#define del_window(b) window_op(del,b)
/*}}}  */
/*}}}  */
/*{{{  buffer handling*/
/*{{{  ind2no*/
private int ind2no(int const i)
{
  return((buff_used<=i || i<0)?0:i+1);
}
/*}}}  */
/*{{{  no2ind*/
#define no2ind(i) ((i)-1)
/*}}}  */
/*{{{  set_buff_id*/
private void set_buff_id(void)
{ int i;

  for (i=buff_used;i--;)
     buffer_list[i]->scr.list_no=ind2no(i);
}
/*}}}  */
/*{{{  set_shift_size*/
private void set_shift_size(void)
{ int i;

  for (i=buff_used;i--;)
     buffer_list[i]->scr.shift_size=SHIFT_PART(buffer_list[i]->scr.txt_size.w);
  prompt_shift_size=SHIFT_PART(screen.w);
}
/*}}}  */
/*{{{  init_buffers*/
private void init_buffers(void)
{
  curr_buff=0;
  buff_used=1;
  dsp_buff=1;
  bd_buffer= -1;
  set_fold_mark_dsp_length(&(init_buffer.f.str));
  if
   (    !(buffer_list=paket_malloc((b_l_size=B_L_PAKET)*sizeof(buffer_data*)))
     || !(buffer_list[curr_buff]=paket_malloc(sizeof(buffer_data)))
   )
     exit_origami(r_mem_full,M_NO_MEMORY);
  *(buffer_list[curr_buff])=init_buffer;
}
/*}}}  */
/*{{{  new_buffer*/
private void new_buffer(boolean const h_s,boolean const rev)
{ buffer_data *bx;
  int sp_buff;
  int i;

  sp_buff=curr_buff;
  /*{{{  maybe extend buffer list*/
  if (buff_used==b_l_size)
   { buffer_data **x;
     size_t n;

     if (!(x=ori_malloc(n=((b_l_size+B_L_PAKET)*sizeof(buffer_data*)))))
        exit_origami(r_mem_full,M_NO_MEMORY);
     memcpy(x,buffer_list,n);
     paket_free(buffer_list);
     buffer_list=x;
     b_l_size+=B_L_PAKET;
   }
  /*}}}  */
  /*{{{  get new buffer*/
  if (!(bx=ori_malloc(sizeof(buffer_data))))
     exit_origami(r_mem_full,M_NO_MEMORY);
  /*}}}  */
  /*{{{  put in list*/
  for (i=buff_used++;i>curr_buff+1;i--) buffer_list[i]=buffer_list[i-1];
  *(buffer_list[++curr_buff]=bx)=init_buffer;
  bx->scr.id=buff_id_used++;
  /*}}}  */
  splitt_window(h_s,rev,sp_buff,bx);
  if (rev)
   /*{{{  change curr and prev*/
   { bx=buffer_list[curr_buff];
     buffer_list[curr_buff]=buffer_list[curr_buff-1];
     buffer_list[--curr_buff]=bx;
   }
   /*}}}  */
  set_buff_id();
}
/*}}}  */
/*{{{  del_buffer*/
private void del_buffer(void)
{ buffer_data *bx=buffer_list[curr_buff];

  paket_free(buffer_list[curr_buff]);
  buff_used--;
  /*{{{  shift buffers*/
  { int i;

    for (i=curr_buff;i<buff_used;i++) buffer_list[i]=buffer_list[i+1];
  }
  /*}}}  */
  if (curr_buff) curr_buff--;
  del_window(bx);
  set_buff_id();
}
/*}}}  */
/*}}}  */
/*{{{  send me a mail concerning dumped file*/
/*{{{  default mail is no mail*/
#ifndef MAIL_DATA
#  define MAIL_DATA
#  define MAIL_OPEN(b)
#  define MAIL_PUT(s)
#  define MAIL_CLOSE()
#endif
/*}}}  */

public void mail_and_dump(int exit_code)
{
  boolean done;
  MAIL_DATA

  { int b;

    save_bd(buffer_list[curr_buff]);
    for (b=0,done=False;b<buff_used;b++)
     { char const *n;

       set_bd(buffer_list[b]);
       if ((n=dump_file()))
        { if (!done)
           { done=True;

             MAIL_OPEN((char*)get_msg(M_MAIL_S));
             /*{{{  write mail header with machine name to the mail*/
             {
#              ifndef NO_MAIL
                  struct utsname mach;
#              endif

               MAIL_PUT
                ( (char*)get_msg
                          ( M_MAIL_1,
                            origami_name,
                            (mach.nodename[0]='\0',uname(&mach),mach.nodename),
                            exit_code
                          )
                );
             }
             /*}}}  */
           }
          MAIL_PUT((char*)get_msg(M_MAIL_2,bd.scr.list_no,(((bd.f.real_tail==bd.f.real_head)?empty_text:get_data(bd.f.real_tail))),n));
        }
     }
  }
  if (done)
   { MAIL_PUT((char*)get_msg(M_MAIL_3));
     MAIL_CLOSE();
   }
}
/*}}}  */
/*{{{  decode_buffer_mouse*/
public int decode_buffer_mouse(int const x, int const y,boolean const m)
{
  int mb;

  /*{{{  get click window*/
  for (mb=buff_used-1;;mb--)
   { scr_dat const *s;
     int z1,z2;

     if (mb<0)
        break;
     s= &buffer_list[mb]->scr;
     if
      (   (z1=s->win.h) && y>(z2=s->off.h) && y<=z1+z2
       && (z1=s->win.w) && x>(z2=s->off.w) && x<=z1+z2
      )
        break;
   }
  /*}}}  */
# ifdef MOUSY
     if (m)
      /*{{{  decode the position in detail, set vars*/
      { buffer_data bd_save;
        int mx,my,mgy,mo;

        if (mb<0)
         /*{{{  menu or status, set positions relativ to area*/
         { mo= (y==message_line)?-2:-1;
           my=y-area_line.h+1;
           mx=x;
         }
         /*}}}  */
        else
         /*{{{  decode the position inside the clicked buffer*/
         {
           /*{{{  save old buffer data and get clicked buffer data*/
           save_bd(&bd_save);
           if (bd_buffer!=mb) set_bd(buffer_list[mb]);
           /*}}}  */
           /*{{{  prepare inside*/
           mo=0;
           /*}}}  */
           /*{{{  set y and mgy, maybe set outside*/
           { int i;

             mgy=i=y-bd.scr.cursor.h-bd.scr.off.h;
             /*{{{  move to line, maybe set outside*/
             while (i>0)
              /*{{{  move down*/
              { if (bd.f.current==bd.f.tail) { mo=2; break; }
                bd.f.current=bd.f.current->next;
                i--;
              }
              /*}}}  */
             while (i<0)
              /*{{{  move up*/
              { if (bd.f.current->prec==bd.f.head) { mo=2;break; }
                bd.f.current=bd.f.current->prec;
                i++;
              }
              /*}}}  */
             /*{{{  if clicked non edit File-fold-braces, outside=1!*/
             if
              (   i==0
               && (!bd.f.entered&&(bd.f.current==bd.f.tail||bd.f.current->prec==bd.f.head))
              ) mo=1;
             /*}}}  */
             /*}}}  */
             /*{{{  get line no*/
             my=line_no(bd.f.current,bd.f.real_head);
             /*}}}  */
           }
           /*}}}  */
           /*{{{  set x*/
           mx=x-bd.scr.off.w+((bd.scr.cursor.h==y)?bd.scr.cur_shift_w:bd.scr.full_shift_w);
           /*}}}  */
           /*{{{  restore buffer data*/
           set_bd(&bd_save);
           /*}}}  */
         }
         /*}}}  */
        ocl_var[var_m_buff].v=ind2no(mb);
        ocl_var[var_m_y].v=my;
        ocl_var[var_m_gy].v=mgy;
        ocl_var[var_m_x].v=mx;
        ocl_var[var_m_out].v=mo;
      }
      /*}}}  */
# endif

  return(ind2no(mb));
}
/*}}}  */
/*{{{  main_editor_loop*/
/*{{{  read_buff*/
public void read_buff(boolean first)
{
  set_bd(buffer_list[curr_buff]);
  if (!first)
     bd.f.real_head=bd.f.real_tail=bd.f.head=bd.f.tail=0;
  if ((arg_list && !start_pipe) || (!first && !filearg[0]))
   /*{{{  read the list of argument files*/
   { filearg=0;
     open_arg_list();
   }
   /*}}}  */
  else
   /*{{{  read file, maybe append pipe*/
   { create_list();
     if (bd.f.real_head!=bd.f.real_tail)
        bd.e.file_no=add_edit_file((char *)get_data(bd.f.real_tail),1,True);
     if (start_pipe)
      /*{{{  append stuff, coming from stdin*/
      { element *x;

        /*{{{  move to end*/
        x=bd.f.tail->prec;
        /*}}}  */
        /*{{{  read file*/
        message(get_msg(F_LOADING,"stdin"));
        bd.f.current=bd.f.tail;
        insert_file
         ( (element *)0,
           bd.f.current->prec,
           bd.f.current,
           False,
           bd.f.real_head,
           (boolean*)0,
           (boolean*)0,
           start_pipe
         );
        fclose(start_pipe);
        start_pipe=0;
        /*}}}  */
        if (x->next!=bd.f.tail)
         /*{{{  move to start of piped text and maybe set file changed*/
         { bd.m.file_changed_status=changed_once;
           title_op(CHGTITLE);
           bd.f.current=x->next;
         }
         /*}}}  */
      }
      /*}}}  */
   }
   /*}}}  */
  /*{{{  update statusline and window title*/
  if (auto_save)
     set_alarm(0,False);
  ori_assert(bd.scr.cur_shift_w<=LINELEN,"shift-check");
  title_op(UPDTITLE);
#  ifdef WINDOW_TITLE_CHANGE
     wt_buff_id= -1;
#  endif
  /*}}}  */
  /*{{{  show read text*/
  find_element((startup_line?startup_line:1),bd.scr.txt_size.h/2);
  startup_line=0;
  /*}}}  */
  /*{{{  init OCL-screen-vars*/
  bd.scr.cursor.w=1;
  /*}}}  */
  call_number_macro(auto_macro);
  arg_list=False;
  save_bd(buffer_list[curr_buff]);
}
/*}}}  */
/*{{{  call_buffer_loop*/
private TOKEN call_buffer_loop(TOKEN ch,int buff)
{
  bd_buffer=buff;
  set_bd(buffer_list[buff]);
  if (bd.scr.win.h && bd.scr.win.w)
   { ch=buffer_loop(ch,buff==curr_buff);
     save_bd(buffer_list[buff]);
   }
  bd_buffer= -1;

  return(ch);
}
/*}}}  */

public RETURNS main_editor_loop(void)
{ TOKEN ch;

  /*{{{  show empty screen with statusline*/
  set_bd(&init_buffer);
  bd.scr.win.h=screen.h-1;
  bd.scr.txt_size.h=bd.scr.win.h-1+var_notitle;
  bd.scr.txt_size.w=bd.scr.win.w=screen.w;
  ClrScr();
  ori_assert(bd.scr.cur_shift_w<=LINELEN,"shift-check");
  title_op(PRTTITLE);
  if (show_string(get_copyright(False),False))
     sleep(1);
  oflush;
  save_bd(&init_buffer);
  /*}}}  */
  /*{{{  init buffers/windows*/
  init_buffers();
  init_window(buffer_list[curr_buff]);
  calc_window();
  /*}}}  */
  read_buff(True);
  set_buff_id();
  warn_mult_edit();
  running=True;
  for (;;)
   { ocl_var[var_us_buff].v=buff_used;
     switch (ch=call_buffer_loop(O_NOP,curr_buff))
      {
        /*{{{  O_DESCRIBE_BINDINGS/O_HELP*/
        case O_DESCRIBE_BINDINGS:
        case O_HELP:
           set_bd(buffer_list[curr_buff]);
           bd.scr.win.h=screen.h-1-root_dont_use.h;
           bd.scr.txt_size.h=bd.scr.win.h-1+var_notitle;
           bd.scr.txt_size.w=screen.w-root_dont_use.w;
           bd.scr.off.h=0;
           bd.scr.off.w=0;
           help(ch==O_HELP);
           goto do_flush;
        /*}}}  */
        /*{{{  O_TITLE_HIDE*/
        case O_TITLE_HIDE:
           if (var_notitle) continue;
           var_notitle=1;
           goto do_flush;
        /*}}}  */
        /*{{{  O_TITLE_SHOW*/
        case O_TITLE_SHOW:
           if (!var_notitle) continue;
           var_notitle=0;
           goto do_flush;
        /*}}}  */
        /*{{{  O_DSP*/
        case O_DSP:
         { boolean loop=ocl_var[var_mod_beh].v==0;
           int cmd_type;

           /*{{{  set all cursor to col 1*/
           { int i;

             for (i=buff_used-1;i>=0;i--)
                buffer_list[i]->scr.cursor.w = 1;
           }
           /*}}}  */
           ocl_var[var_ocl_arg].v=
              ((dsp.ctrl==ictrl_dsp) ?  1 : 0)
            + (numb_dsp(dsp.ctrl)    ?  2 : 0)
            + (numb_dsp(dsp.high)    ?  4 : 0)
            + (numb_dsp(dsp.norm)    ?  8 : 0)
            + ((dsp.base==oct_dsp)   ? 16 : 0)
            + ((dsp.base==dec_dsp)   ? 32 : 0)
            + dsp.tab_size*64;
           cmd_type=menu_item(get_msg(M_DSP,dsp.tab_size),0,False,True);
           switch (cmd_type)
            {
              /*{{{  0 -> quit*/
              case 0:
                 no_message();
                 break;
              /*}}}  */
              /*{{{  7 -> tab width: prompt for*/
              case 7:
               {
#                define NBSIZE ((sizeof(int)<<2)+1)
                 unsigned char tab_txt[NBSIZE];

                 s_readprompt(tab_txt,get_msg(M_TABSIZE),NBSIZE-1,misc_history);
                 if (!aborted)
                  { cmd_type= -atoi((char*)tab_txt);
                    if (cmd_type>0)
                       cmd_type=0;
                  }
                 else
              default:
                    cmd_type='c';
                 goto chg_mode;
               }
              /*}}}  */
              /*{{{  1-6,8-10 pass code*/
              case 1:
              case 2:
              case 3:
              case 4:
              case 5:
              case 6:
              case 8:
              case 9:
              case 10:
                 cmd_type="odhmin p8a"[cmd_type-1];
                 goto chg_mode;
              /*}}}  */
              chg_mode:
                chg_dsp_type(cmd_type);
                /*{{{  calculate the size of the fold mark displays*/
                { int i;

                  for (i=buff_used-1;i>=0;i--)
                     set_fold_mark_dsp_length(&(buffer_list[i]->f.str));
                }
                /*}}}  */
                if (loop)
                 /*{{{  push macro to stay in loop*/
                 { static TOKEN looping[]={ O_DSP,M_END_MACRO };

                   push_macro(looping);
                 }
                 /*}}}  */
                else
                   no_message();
                goto do_flush;
            }
           break;
         }
        /*}}}  */
        /*{{{  O_GROW_BUFFER:*/
        case O_GROW_BUFFER:
           if (window_op(h_grow,(buffer_data*)0))
              goto buffs_size_failed;
           goto do_flush;
        /*}}}  */
        /*{{{  O_SHRINK_BUFFER:*/
        case O_SHRINK_BUFFER:
           if (window_op(h_shrink,(buffer_data*)0))
              goto buffs_size_failed;
           goto do_flush;
        /*}}}  */
        /*{{{  O_GROW_W_BUFFER:*/
        case O_GROW_W_BUFFER:
           if (window_op(w_grow,(buffer_data*)0))
              goto buffs_size_failed;
           goto do_flush;
        /*}}}  */
        /*{{{  O_SHRINK_W_BUFFER:*/
        case O_SHRINK_W_BUFFER:
           if (window_op(w_shrink,(buffer_data*)0))
            { buffs_size_failed:
              msg_message(M_FAILED);
              break;
            }
           goto do_flush;
        /*}}}  */
        /*{{{  M_GO_BUFFER*/
        case M_GO_BUFFER:
         { int n;
           int t;

           t=get_arg("go-biff-type");
           n=ocl_var[get_arg("go-buff-no")].v;
           if (t==1)
            /*{{{  use id as target*/
            { int j;

              for (j=0;;j++)
                 if (j==buff_used)
                     goto no_more_buffs;
                 else if (n==buffer_list[j]->scr.id)
                  { n=j;
                    break;
                  }
            }
            /*}}}  */
           else
            /*{{{  use list no as target*/
            n=no2ind(n);
            /*}}}  */
           if (go_window(n))
            /*{{{  error report: no more buffers*/
            { no_more_buffs:
              msg_message(M_NO_BUFFERS);
              break;
            }
            /*}}}  */
           goto do_flush;
         }
        /*}}}  */
        /*{{{  O_OPEN_[LIST_][W_]BUFFER*/
        case O_OPEN_BUFFER:
        case O_OPEN_W_BUFFER:
        case O_OPEN_LIST_BUFFER:
        case O_OPEN_LIST_W_BUFFER:
         { boolean rev;

           rev=(ocl_var[var_mod_beh].v>0)||(ocl_var[var_mod_beh].v==-1);
           /*{{{  set filearg to new filename*/
           if (ch==O_OPEN_LIST_BUFFER || ch==O_OPEN_LIST_W_BUFFER)
             /*{{{  prompt for number and decode it*/
             { s_readprompt(print_buffer,get_msg(M_FILEPO),15,misc_history);
               if (aborted) break;
               filearg=fileno2name(atoi((char*)print_buffer));
             }
             /*}}}  */
           else
#           ifdef OS_NULL_DEVICE
           if (ocl_var[var_mod_beh].v<0)
              filearg=(unsigned char*)OS_NULL_DEVICE;
           else
#           endif
            /*{{{  prompt for filename*/
            { if ((!(*fileprompt(print_buffer))) || aborted) break;
              filearg=print_buffer;
            }
            /*}}}  */
           /*}}}  */
           new_buffer((ch==O_OPEN_BUFFER || ch==O_OPEN_LIST_BUFFER),rev);
           read_buff(False);
           warn_mult_edit();
           call_number_macro(buff_macro);
           goto do_flush;
         }
        /*}}}  */
        /*{{{  O_A_AUTO_SAVE*/
        case O_A_AUTO_SAVE:
           if (ocl_var[var_mod_beh].v>0)
            /*{{{  seconds from modify-behaviour*/
            { if (!auto_save)
                 title_op(CHGTITLE);
              auto_save = True;
              set_alarm(ocl_var[var_mod_beh].v,True);
            }
            /*}}}  */
           else
            /*{{{  prompts for minute*/
            { unsigned char time[12];

              s_readprompt(time, (unsigned char*)"auto-save-interval", 10,no_history);
              if (!aborted) {
                if (!auto_save)
                   title_op(CHGTITLE);
                auto_save = True;
                set_alarm(atoi((char *)time),False);
              }
            }
            /*}}}  */
           break;
        /*}}}  */
        /*{{{  O_D_AUTO_SAVE*/
        case O_D_AUTO_SAVE:
           ocl_var[var_ocl_arg].v=auto_save?alarm_time:0;
           if (auto_save)
              title_op(CHGTITLE);
           auto_save = False;
           reset_alarm();
           break;
        /*}}}  */
        /*{{{  O_AUTO_SAVE*/
        case O_AUTO_SAVE:
           set_alarm(0,False);
           if (salarm_macro)
            { call_number_macro(salarm_macro);
              break;
            }
           else
              goto do_for_all;
        /*}}}  */
        /*{{{  O_[A|D]_NOPARSE*/
        case O_D_NOPARSE:
        case O_A_NOPARSE:
           set_bd(buffer_list[curr_buff]);
           ocl_var[var_ocl_arg].v=bd.e.fold_in?0:1;
           init_buffer.e.fold_in=bd.e.fold_in=(ch==O_A_NOPARSE);
           title_op(CHGTITLE);
           save_bd(buffer_list[curr_buff]);
           break;
        /*}}}  */
        /*{{{  QUIT's*/
        { RETURNS exit_code;

        case M_FINISH:
           exit_code=ocl_var[get_arg("exit")].v;
           prompt_string(print_buffer);
        case O_FINISH:
        case O_QUIT:
           if (buff_used>1)
            /*{{{  delete current buffer*/
            { set_bd(buffer_list[curr_buff]);
              delete_list(bd.f.real_head, bd.f.real_tail);
              set_0_data(bd.f.real_tail);
              set_linetyp(*bd.f.real_tail,NOT_FOLD);
              proc_dispose(bd.f.real_tail);
              set_0_data(bd.f.real_head);
              set_linetyp(*bd.f.real_head,NOT_FOLD);
              proc_dispose(bd.f.real_head);
              del_buffer();
              warn_mult_edit();
              call_number_macro(buff_macro);
              goto do_flush;
            }
            /*}}}  */
           else
            /*{{{  exit the editor*/
            { if (ch!=M_FINISH)
               { exit_code=(bd.m.file_changed_status!=unchanged_file)?r_file_nok:r_ok;
                 print_buffer[0]='\0';
               }
              return(exit_code);
            }
            /*}}}  */
        }
        /*}}}  */
        /*{{{  M_LAYOUT*/
        case M_LAYOUT:
           if (win_layout(get_arg("layout-command")))
              goto do_flush;
           break;
        /*}}}  */
        /*{{{  O_FLUSH*/
        case O_FLUSH:
         { int x=executing_macro?ocl_var[get_arg("flush-line")].v:0;

           if (x>=1 || x<=buffer_list[curr_buff]->scr.txt_size.h)
              buffer_list[curr_buff]->scr.cursor.h=x;
        do_flush:
           calc_window();
           ch=O_FLUSH;
           restore_area();
           goto do_for_all;
         }
        /*}}}  */
        /*{{{  O_REFRESH*/
        case O_REFRESH:
           if (get_terminal_capability())
              return(r_init_err);
           if (ocl_var[var_mod_beh].v==0)
              B_invalid();
           /*{{{  window?*/
#           if defined(SIGWINCH) || defined(MGR)
              if (win_changed && !scr_off)
               { win_changed = False;
                 verbose_msg_message(M_WIN_CHANGED);
               }
#           endif
           /*}}}  */
           init_root_window_size();
           calc_window();
           restore_area();
           ch=O_REFRESH;
        do_for_all:
          /*{{{  try to do ch in all buffers*/
          { int i;

            for (i=buff_used-1;i>=0;i--)
               call_buffer_loop(ch,i);
            continue;
          }
          /*}}}  */
        /*}}}  */
        default:
           continue;
      }
   }
}
/*}}}  */
