/*ProfiPacket - packet radio terminal program
  Copyright (C) 1999  Alexander Feigl

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  Author:

  Alexander Feigl
  Burachstraße 51

  D-88250 Weingarten

  Mail : Alexander.Feigl@gmx.de
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef __GNUC__
#define _storage_text_ __attribute__ ((section(".text")))
#else
#define _storage_text_
#endif


#include <libraries/mui.h>

#include "Editor.h"
#include "EditorCommon.h"
#include "EditorPrivate.h"

unsigned int RelocateMemory (struct EditorBuffer *MoveBuffer,
                             unsigned char *MovePointer,
                             signed long MovingLength);
void memcpyfast(void *Source,void *Destination,unsigned long Bytes);
struct LineCache *GetLineCache (struct Class_Data *data,unsigned long line);
unsigned long GetCharX(struct Class_Data *data,unsigned short chr);

typedef const unsigned char *cstring;

const cstring _storage_text_ ControlChars[32] =
   { (cstring)"<NULL>",
     (cstring)"<CTRL-A>",
     (cstring)"<CTRL-B>",
     (cstring)"<CTRL-C>",
     (cstring)"<CTRL-D>",
     (cstring)"<CTRL-E>",
     (cstring)"<CTRL-F>",
     (cstring)"<CTRL-G>",
     (cstring)"<CTRL-H>",
     (cstring)"<CTRL-I>",
     (cstring)"<CTRL-J>",
     (cstring)"<CTRL-K>",
     (cstring)"<CTRL-L>",
     (cstring)"<CTRL-M>",
     (cstring)"<CTRL-N>",
     (cstring)"<CTRL-O>",
     (cstring)"<CTRL-P>",
     (cstring)"<CTRL-Q>",
     (cstring)"<CTRL-R>",
     (cstring)"<CTRL-S>",
     (cstring)"<CTRL-T>",
     (cstring)"<CTRL-U>",
     (cstring)"<CTRL-V>",
     (cstring)"<CTRL-W>",
     (cstring)"<CTRL-X>",
     (cstring)"<CTRL-Y>",
     (cstring)"<CTRL-Z>",
     (cstring)"<ESC>",
     (cstring)"<0x1c>",
     (cstring)"<0x1d>",
     (cstring)"<0x1e>",
     (cstring)"<0x1f>",
 };

unsigned int InsertLine(struct Class_Data *data,struct EditorBuffer *edbuf,
                        unsigned long LineAfterInsert)
 {

  unsigned long StyleSize;
  unsigned long CacheSize;
  unsigned long MemNeeded;
  unsigned long MovingInfos,MovingSize;
  signed long XLineAfterInsert;
  signed long oldgarb;
  struct LineCache *CurrentLine;
  struct StyleInfo *CurrentStyle,*PreStyle;

  oldgarb=data->GarbagedLines;


  if (CacheClear(data)==FALSE)
   {
    return (FALSE);
   }
 
  XLineAfterInsert=LineAfterInsert+oldgarb-data->GarbagedLines;
  if (XLineAfterInsert<0) return (FALSE);  

  StyleSize=sizeof (struct StyleInfo);
  CacheSize=sizeof (struct LineCache);
  MemNeeded=StyleSize+CacheSize;
  if (GetFreeMemory(edbuf)<MemNeeded)
   {
    GarbageCollection(data,edbuf);
    if (GetFreeMemory(edbuf)<MemNeeded)
     {
      return (FALSE);
     }
   }

  XLineAfterInsert=LineAfterInsert+oldgarb-data->GarbagedLines;
  if (XLineAfterInsert<0) return (FALSE);  
 
  if (edbuf->BufferLineCache < XLineAfterInsert)
     {
      return (FALSE);
     }
 
  CurrentLine=(struct LineCache *) (edbuf->EditorMem+
                                    edbuf->BufferSize) -
                                   (XLineAfterInsert+1);
 
  MovingInfos=edbuf->BufferLineCache-XLineAfterInsert;

  if (MovingInfos!=0)
    {
     MovingSize=sizeof(struct LineCache)*MovingInfos;
     memcpyfast(CurrentLine-MovingInfos+1,CurrentLine-MovingInfos
                ,MovingSize);
    }
   else
   {
    CurrentLine->LineMemory=edbuf->EditorMem+edbuf->BufferFilled;
   }
  
  CurrentLine->LineLength=0;
  CurrentLine->StyleInfos=1;
  edbuf->BufferLineCache++;

  if (RelocateMemory(edbuf,CurrentLine->LineMemory,StyleSize)==FALSE)
      {
       return (FALSE);
      }

 
  CurrentStyle=(void *) CurrentLine->LineMemory;

  if ( (XLineAfterInsert!=0) && ((CurrentLine+1)->StyleInfos!=0) )
   {
    PreStyle=(struct StyleInfo *) ( (CurrentLine+1)->LineMemory)+
                        ((CurrentLine+1)->StyleInfos-1) ;
    CurrentStyle->BackgroundColor=PreStyle->BackgroundColor;
    CurrentStyle->ForegroundColor=PreStyle->ForegroundColor;
    CurrentStyle->TextStyle=PreStyle->TextStyle;
    CurrentStyle->StartColumn=0;
   }
   else
   {
    CurrentStyle->BackgroundColor=0;
    CurrentStyle->ForegroundColor=1;
    CurrentStyle->TextStyle=0;
    CurrentStyle->StartColumn=0;
    }


  if ( (edbuf->InputLine!=-1) && (edbuf->InputLine>=XLineAfterInsert))
     edbuf->InputLine++;
      
  if ( (edbuf->MarkStartLine!=-1) && (edbuf->MarkStartLine>=XLineAfterInsert))
     edbuf->MarkStartLine++;

  if ( (edbuf->MarkStopLine!=-1) && (edbuf->MarkStopLine>=XLineAfterInsert))
     edbuf->MarkStopLine++;
 

  return (TRUE);
 }

unsigned long GetCharX(struct Class_Data *data,unsigned short chr)
{
 if ((chr & 0xff )>=32) return (data->FontXSize[chr & 0xff]);
 if (!( (1<<(chr & 0x1f) ) & data->Unprintable  )) return (data->FontXSize[chr & 0xff]);
  {
   unsigned long size=0;
   const char *sptr;
   sptr=ControlChars[chr & 0x1f];
   while (*(sptr)!='\0')
    {
     size+=data->FontXSize[ ((unsigned short) (*(sptr++))) & 0xff];
    }
   return(size);
  }
}

unsigned long OffsetToColumn(struct Class_Data *data,struct LineInfo *li,
                             unsigned long offset)
{
 unsigned long coli,i,crest;
 unsigned char *cptr;
 coli=0;
 i=0;
 crest=li->CharLen;
 cptr=li->Chars;
 while (i<offset)
  {
   if (crest!=0)
    {
     i+=GetCharX(data,*(cptr++));
     crest--;
    }
    else
    {
     i+=GetCharX(data,' ');
    }
   coli++;
  }
 return (coli);
}

unsigned long OffsetToColumnMouse(struct Class_Data *data,struct LineInfo *li,
                             unsigned long offset)
{
 unsigned long coli,i,j,crest;
 unsigned char *cptr;
 coli=0;
 i=0;
 crest=li->CharLen;
 cptr=li->Chars;
 while (crest!=0)
  {
   j=GetCharX(data,*(cptr++));
   crest--;
   if (offset<(i+j)) break;
   i+=j;
   coli++;
  } 
 return (coli);
}

unsigned long ColumnXSize(struct Class_Data *data,struct LineInfo *li,
                         unsigned long column)
{
 if (column>=(li->CharLen))
  {
   return (GetCharX(data,' '));
  }
 return (GetCharX(data,*(li->Chars+column)));
}

unsigned long ColumnToOffset(struct Class_Data *data,struct LineInfo *li,
                             unsigned long column)
{
 unsigned long offi,i,crest;
 unsigned char *cptr;
 offi=0;
 i=0;
 crest=li->CharLen;
 cptr=li->Chars;
 while (i<column)
  {
   if (crest!=0)
    {
     offi+=GetCharX(data,*(cptr++));
     crest--;
    }
    else
    {
     offi+=GetCharX(data,' ');
    }
   i++;
  }
 return (offi);
}


unsigned long FillDisplayCache(struct Class_Data *data,struct LineInfo *lc)
{
 unsigned long restlen;
 unsigned long reststy;
 unsigned char *nextchr;
 struct StyleInfo *nextsty;
 unsigned long thiscol=0;
 unsigned long thisx;

 unsigned short domark;
 signed long markstart,markstop,doxmark;

 data->DisplayX=0;
 data->DisplayLength=0;
 restlen=lc->CharLen;
 reststy=lc->StyleLen;
 nextchr=lc->Chars;
 nextsty=lc->Styles;    
 domark=FALSE;
 markstart=0;
 markstop=0;

 if (lc->edi==data->DisplayPage)
  {
   struct EditorBuffer *edbuf;
   edbuf=data->Buffers[data->DisplayPage];
   if ( (lc->line>=edbuf->MarkStartLine) &&
        (lc->line<=edbuf->MarkStopLine) &&
        (lc->Chars!=0) )
    {
     domark=TRUE;
     markstart=0;
     markstop=lc->CharLen-1;
     if (lc->line==edbuf->MarkStartLine) markstart=edbuf->MarkStartColumn;
     if (lc->line==edbuf->MarkStopLine) markstop=edbuf->MarkStopColumn;
    }
  }
 
 if ( (reststy!=0) && (nextsty->StartColumn==0)  )
  {
   data->DisplayAPen=nextsty->ForegroundColor;
   data->DisplayBPen=nextsty->BackgroundColor;
   data->DisplayStyle=nextsty->TextStyle;
   ++nextsty;
   --reststy;
  }
  else
  {
   data->DisplayAPen=1;
   data->DisplayBPen=0;
   data->DisplayStyle=0;
  }
  
 while
       ( (data->DisplayX<data->DisplayOffset) || (thiscol<data->DisplayStart) )
  {
   if ( (restlen==0) || (thiscol>=data->DisplayStop) )
    {
     return (0);
    }
   data->DisplayX+=GetCharX(data,*nextchr);
   ++thiscol;
   ++nextchr;
   --restlen;
   if ( (reststy!=0) && (nextsty->StartColumn==thiscol)  )
    {
     data->DisplayAPen=nextsty->ForegroundColor;
     data->DisplayBPen=nextsty->BackgroundColor;
     data->DisplayStyle=nextsty->TextStyle;
     ++nextsty;
     --reststy;
    }
  }
 
 if ( (domark==TRUE) && (markstart<=thiscol) && (markstop>=thiscol) )
  {
   unsigned long t;
   t=data->DisplayAPen;
   data->DisplayAPen=data->DisplayBPen;
   data->DisplayBPen=t;
   doxmark=markstop+1;
  }
  else
  {
   doxmark=markstart;
  }
 
 data->DisplayDrMd=((data->DisplayBPen==0) && (!data->SolidBackground))?0:1;
 data->DisplayAPen=MUIPEN(data->ANSIPens[data->DisplayAPen]);
 data->DisplayBPen=MUIPEN(data->ANSIPens[data->DisplayBPen]);
 data->DisplayStart=thiscol;
 data->DisplayX-=data->DisplayOffset;
 data->DisplayXSize=0;
 
 while (1)
  {
   if (domark==TRUE)
    {
     if (thiscol==doxmark) return (data->DisplayLength);
    }
   if (
        ( (reststy!=0) && (nextsty->StartColumn<=thiscol) ) ||
        ( thiscol>data->DisplayStop) || (restlen==0) )      
    {
     return (data->DisplayLength);
    }
   thisx=GetCharX(data,*nextchr);
   if (thisx+data->DisplayXSize+data->DisplayX > data->DisplayXMax)
    {
     return (data->DisplayLength);
    }
   if (data->DisplayLength>=80) 
    {
     return (data->DisplayLength);
    }

   data->DisplayXSize+=thisx;
   
   if ( (*nextchr>=32) || ( !(1<<(*nextchr) & data->Unprintable ) ) )
    {
     data->DisplayCache[data->DisplayLength]=*nextchr;
     data->DisplayLength++;
    }
    else
    {
     const char *sptr;
     sptr=ControlChars[ ( ((unsigned short) (*nextchr)) & 0xff)];
     while ( *sptr!='\0')
      {
       data->DisplayCache[data->DisplayLength++]=*(sptr++);       
      } 
    }

   
   data->DisplayStart++;
   nextchr++;
   restlen--;
   thiscol++;
  }
}

unsigned int RelocateMemory (struct EditorBuffer *MoveBuffer,
                             unsigned char *MovePointer,
                             signed long MovingLength)
{
 unsigned long i;
 unsigned short firsthit=TRUE;
 struct LineCache *MovingLine;
 if (MovingLength==0) return(TRUE);
 if (MovingLength+MoveBuffer->BufferFilled
     +(sizeof(struct LineCache)*MoveBuffer->BufferLineCache )
      >MoveBuffer->BufferSize)
  {
   return (FALSE);
  } 

 if (MovingLength<0)
  {
   memcpyfast(MovePointer-MovingLength,MovePointer,
              MoveBuffer->BufferFilled-(MovePointer-MoveBuffer->EditorMem)+
              MovingLength);
   MoveBuffer->BufferFilled+=MovingLength;
  }
 if (MovingLength>0)
  {
   memcpyfast(MovePointer,MovePointer+MovingLength,
              MoveBuffer->BufferFilled-(MovePointer-MoveBuffer->EditorMem));
   MoveBuffer->BufferFilled+=MovingLength;
  }
 MovingLine=(struct LineCache *) 
            (MoveBuffer->EditorMem+MoveBuffer->BufferSize) - 1;

 for (i=0;i<MoveBuffer->BufferLineCache;++i,--MovingLine)
  {
   if (MovingLine->LineMemory==MovePointer)
    {
     if (firsthit!=FALSE)
      {
       firsthit=FALSE;
      }
      else
      {
       MovingLine->LineMemory+=MovingLength;
      }
    }
    else
    {
     if (MovingLine->LineMemory>MovePointer)
      {
       MovingLine->LineMemory+=MovingLength;
      }
    }
  }
 return(TRUE);
}


unsigned long GetFreeMemory (struct EditorBuffer *buffer)
 {
  return (buffer->BufferSize-buffer->BufferFilled-
          (buffer->BufferLineCache*sizeof(struct LineCache)));
 }




void GarbageCollection (struct Class_Data *data,struct EditorBuffer *buffer)
 {
  unsigned short thischannel,dodisplay;

  thischannel=FALSE;
  dodisplay=FALSE;
  if (data->Buffers[data->DisplayPage]==buffer)
   {
    thischannel=TRUE;
    if (data->ValidDisplay==TRUE)
     {
      dodisplay=TRUE;
     }
   }
  if ( (data->GarbageEditor==FALSE ) && (data->FreeMoving==FALSE) )
     return;     /* Soory, cannot garbage */

  if (data->FreeMoving!=FALSE)
   {
    struct LineCache *lc;
    while (buffer->BufferLineCache>(buffer->CursorLine+1) )
     {
      lc=(struct LineCache *) (buffer->EditorMem+buffer->BufferSize)-
                (buffer->BufferLineCache);
      if (lc->LineLength!=0) break;
      buffer->BufferLineCache--;
      buffer->BufferFilled-= (lc->LineLength+3) & 0xfffffffc;
      buffer->BufferFilled-= sizeof(struct StyleInfo) * lc->StyleInfos;
     }
   }
  if (data->GarbageEditor!=FALSE)
   {
    signed long WantFree;
    signed long IsFree;
    signed long GetFree;
    unsigned long StripLines;
    unsigned long i;
    struct LineCache *lc;
    IsFree=GetFreeMemory(buffer);
    WantFree=buffer->BufferSize/16;
    if (WantFree<512) WantFree=512;
    if (IsFree>WantFree) return;
     {
      unsigned short doref;
      doref=FALSE;
      WantFree-=IsFree;
      StripLines=0;
      lc=(struct LineCache *) (buffer->EditorMem+buffer->BufferSize);
      
      IsFree=0;

      while (StripLines< ( buffer->CursorLine+1) )
       {
        lc--;
        GetFree=(lc->LineLength+3) & 0xfffffffc;
        GetFree+=(lc->StyleInfos)*sizeof (struct StyleInfo);
        WantFree-=GetFree;
        IsFree+=GetFree;
        StripLines++;
        if (WantFree<0) break;
       }
      
      if ( (thischannel==TRUE) && (data->CachedLine!=-1) &&
           (data->CachedLine<StripLines) ) return;

      data->GarbagedLines+=StripLines;
      buffer->BufferFilled-=IsFree;
      memcpyfast(buffer->EditorMem+IsFree,buffer->EditorMem,
                 buffer->BufferFilled);
      lc=(struct LineCache *) (buffer->EditorMem+buffer->BufferSize);
      buffer->BufferLineCache-=StripLines;
      memcpyfast(lc-buffer->BufferLineCache-StripLines,
                 lc-buffer->BufferLineCache,
                 sizeof(struct LineCache)*buffer->BufferLineCache);
      lc--;
      for (i=0;i<buffer->BufferLineCache;++i,lc--)
       {
        lc->LineMemory-=IsFree;
       }
      if (buffer->HeadLine<StripLines)
       {
        buffer->HeadLine=0;
        doref=TRUE;
       }
       else
       {
        buffer->HeadLine-=StripLines;
       }
      if (buffer->CursorLine<StripLines)
       {
        buffer->CursorLine=0;
        doref=TRUE;
       }
       else
       {
        buffer->CursorLine-=StripLines;
       }
      if ( (buffer->InputLine!=-1) && (buffer->InputLine<StripLines) )
       {
        buffer->InputLine=-1;
       }
       else
       {
        if (buffer->InputLine!=-1) buffer->InputLine-=StripLines;
       }

      if ( (buffer->MarkStartLine!=-1) && (buffer->MarkStartLine<StripLines) )
       {
        buffer->MarkStartLine=-1;
        buffer->MarkStartColumn=-1;
        buffer->MarkStopLine=-1;
        buffer->MarkStopColumn=-1;
        doref=TRUE;
       }
       else
       {
        if (buffer->MarkStartLine!=-1) buffer->MarkStartLine-=StripLines;
       }

      if ( (buffer->MarkStopLine!=-1) && (buffer->MarkStopLine<StripLines) )
       {
        buffer->MarkStartLine=-1;
        buffer->MarkStartColumn=-1;
        buffer->MarkStopLine=-1;
        buffer->MarkStopColumn=-1;
        doref=TRUE;
       }
       else
       {
        if (buffer->MarkStopLine!=-1) buffer->MarkStopLine-=StripLines;
       }
     
      if ( (thischannel==TRUE) && (data->CachedLine!=-1) )
       {
        data->CachedLine-=StripLines;
       }
      if ( (doref==TRUE) && (dodisplay==TRUE) )
       {
        CompleteRefresh(data);
       }
     } 
   }
   {
    signed long MaxLine;
    unsigned long refresh;
    refresh=FALSE;
    MaxLine=buffer->BufferLineCache-1;
    if (buffer->HeadLine>MaxLine) 
     {
      buffer->HeadLine=MaxLine;
      buffer->HeadColumn=0;
      refresh=TRUE;
     }
    if (buffer->CursorLine>(MaxLine+1))
     {
      buffer->CursorLine=MaxLine;
      buffer->CursorColumn=0;
      refresh=TRUE;
     }
    if (buffer->InputLine>MaxLine)
     {
      buffer->InputLine=-1;
      refresh=TRUE;
     }
    if ( (buffer->MarkStartLine>MaxLine) || (buffer->MarkStopLine>MaxLine) )
     {
      buffer->MarkStartLine=-1;
      buffer->MarkStartColumn=-1;
      buffer->MarkStopLine=-1;
      buffer->MarkStopColumn=-1;
      refresh=TRUE;
     }
    if ( (refresh==TRUE) && (dodisplay==TRUE) )
     {
      CompleteRefresh(data);
     }
   }

 }  

struct LineCache *GetLineCache (struct Class_Data *data,unsigned long line)
 {
  struct EditorBuffer *CurrentPage;
  struct LineCache *CurrentLine;
  signed long oldblc;
  signed long isfirst;
  signed long xline;

  xline=line;
  isfirst=TRUE;
  CurrentPage= data->Buffers[data->DisplayPage];
  
  if (CurrentPage->BufferLineCache > xline)
   {
    CurrentLine=(struct LineCache *) (CurrentPage->EditorMem+
                                     CurrentPage->BufferSize) -
                (xline+1);
    return (CurrentLine);
   }
 
  CurrentLine=(struct LineCache *) (CurrentPage->EditorMem+
                                     CurrentPage->BufferSize) -
              (CurrentPage->BufferLineCache+1);

  while ( CurrentPage->BufferLineCache <= xline)
   {
    if (GetFreeMemory(CurrentPage)<(sizeof(struct LineCache)
                                   +sizeof(struct StyleInfo)))
     {
      if (isfirst==TRUE)
       {
        isfirst=FALSE;
        oldblc=data->GarbagedLines;
        GarbageCollection(data,CurrentPage);
        xline=xline+oldblc-data->GarbagedLines;
        CurrentLine=(struct LineCache *) (CurrentPage->EditorMem+
                                         CurrentPage->BufferSize) -
                   (CurrentPage->BufferLineCache+1);
        continue;
       }
       else
       {
        return (NULL);       
       }
     }
    isfirst=TRUE;
    if (CurrentPage->BufferLineCache==0)
     {
      struct StyleInfo *CurrentStyle;
      CurrentLine->LineLength=0;
      CurrentLine->StyleInfos=1;
      CurrentLine->LineMemory=CurrentPage->EditorMem;
      CurrentStyle=(void *) (CurrentLine->LineMemory);
      CurrentStyle->BackgroundColor=0;
      CurrentStyle->ForegroundColor=1;
      CurrentStyle->TextStyle=0;
      CurrentStyle->StartColumn=0;
     }
     else
     {   
      struct StyleInfo *CurrentStyle;
      struct StyleInfo *PreStyle;
      CurrentLine->LineLength=0;
      CurrentLine->StyleInfos=1;
      CurrentLine->LineMemory=(CurrentLine+1)->LineMemory+ 
                              (
                               ( ( (CurrentLine+1)->LineLength +3 ) & 0xfffffffc ) +
                               ( (CurrentLine+1)->StyleInfos* sizeof (struct StyleInfo))
                              );
      CurrentStyle=(void *)(CurrentLine->LineMemory);
      PreStyle=(struct StyleInfo *) 
            ((CurrentLine+1)->LineMemory)+((CurrentLine+1)->StyleInfos-1);
      CurrentStyle->BackgroundColor=PreStyle->BackgroundColor;
      CurrentStyle->ForegroundColor=PreStyle->ForegroundColor;
      CurrentStyle->TextStyle=PreStyle->TextStyle;
      CurrentStyle->StartColumn=0;
      
     }
    CurrentLine--;
    CurrentPage->BufferFilled+=sizeof(struct StyleInfo);
    CurrentPage->BufferLineCache++;
   }

  return (CurrentLine+1);
 }

unsigned int DeleteLine (struct Class_Data *data,unsigned long line)
 {
  struct LineCache *ThisLine,*FirstLine;
  unsigned long MemoryUsed,MemoryAfter,xline,i;
  unsigned char *MemoryPtr;
  struct EditorBuffer *edbuf;

  if (CacheClear(data)==FALSE) return(FALSE);

  edbuf=data->Buffers[data->DisplayPage];

  if ( (ThisLine=GetLineCache(data,line)) == NULL) return (FALSE);

  MemoryUsed=((ThisLine->LineLength+3) & 0xfffffffc) +
               sizeof (struct StyleInfo) * ThisLine->StyleInfos;
  MemoryPtr=ThisLine->LineMemory;
  MemoryAfter=edbuf->BufferFilled-(MemoryPtr-edbuf->EditorMem)-MemoryUsed;
  edbuf->BufferFilled-=MemoryUsed;
  memcpyfast(MemoryPtr+MemoryUsed,MemoryPtr,MemoryAfter);
  FirstLine=(struct LineCache *) (edbuf->EditorMem+edbuf->BufferSize);
  xline=FirstLine-ThisLine;
  edbuf->BufferLineCache--;
  for (i=xline;i<=edbuf->BufferLineCache;++i)
   {
    ThisLine->LineLength=(ThisLine-1)->LineLength;
    ThisLine->StyleInfos=(ThisLine-1)->StyleInfos;
    ThisLine->LineMemory=(ThisLine-1)->LineMemory-MemoryUsed;
    ThisLine--;
   }
  if ( (edbuf->HeadLine>=line) && (edbuf->HeadLine!=0) )
    {
     edbuf->HeadLine--;
    }
  if ( (edbuf->CursorLine>=line) && (edbuf->CursorLine!=0) )
    {
     edbuf->CursorLine--;
    }
  if ( (edbuf->InputLine>=line) && (edbuf->InputLine!=0) )
    {
     edbuf->InputLine--;
    }
  if ( (edbuf->MarkStartLine!=-1) )
   {
    if ( (edbuf->MarkStartLine>=line) && (edbuf->MarkStartLine!=0) )
      {
       edbuf->MarkStartLine--;
      }
    if ( (edbuf->MarkStopLine>=line) && (edbuf->MarkStopLine!=0) )
      {
       edbuf->MarkStopLine--;
      }
   }
  CompleteRefresh(data);
  return(TRUE);
 }

unsigned int CacheSet (struct Class_Data *data,unsigned long line)
 {
  struct LineCache *ThisLine;
  signed long oldgarbage;
  if (data->CachedLine == line) return (TRUE);
  if (data->CachedLine != -1 )  return (FALSE);
  
  oldgarbage=data->GarbagedLines;
  if ( (ThisLine=GetLineCache(data,line)) == NULL) return (FALSE);
  data->CachedStyleInfo=ThisLine->StyleInfos;
  data->CachedTextLen=ThisLine->LineLength;
  data->CachedLine=line-data->GarbagedLines+oldgarbage;

  memcpyfast (ThisLine->LineMemory,data->CachedStyle,
              sizeof(struct StyleInfo)* data->CachedStyleInfo);
  memcpyfast (ThisLine->LineMemory+
              (sizeof(struct StyleInfo)* data->CachedStyleInfo),
              data->CachedChar,(data->CachedTextLen+3) & 0xfffffffc);
  
  return (TRUE);
 }



unsigned int CacheClear (struct Class_Data *data)
 {
  signed long MemoryCached;
  signed long MemoryUncached;
  signed long MemoryMissing;
  struct LineCache *CachePointer;


  if (data->CachedLine == -1 ) return (TRUE);

  MemoryCached=((data->CachedTextLen+3) & 0xfffffffc) + 
               sizeof (struct StyleInfo) * data->CachedStyleInfo;
  CachePointer=GetLineCache(data,data->CachedLine);
  MemoryUncached=((CachePointer->LineLength+3) & 0xfffffffc) +
               sizeof (struct StyleInfo) * CachePointer->StyleInfos;
  MemoryMissing=MemoryCached-MemoryUncached;
 
  if ( (MemoryMissing>0) && (GetFreeMemory(data->Buffers[data->DisplayPage])
                             <MemoryMissing) )
    {
     GarbageCollection(data,data->Buffers[data->DisplayPage]);
     CachePointer=GetLineCache(data,data->CachedLine);
    }

  if (MemoryMissing!=0)
   {
    if (RelocateMemory(data->Buffers[data->DisplayPage],CachePointer->LineMemory,
                   MemoryMissing)==FALSE)
     {
        data->CachedLine=-1;
        return (FALSE);      
     }
   }
  CachePointer->LineLength=data->CachedTextLen;
  CachePointer->StyleInfos=data->CachedStyleInfo;
  memcpyfast (data->CachedStyle,CachePointer->LineMemory,
              sizeof(struct StyleInfo)* data->CachedStyleInfo);
  memcpyfast (data->CachedChar,CachePointer->LineMemory+
              (sizeof(struct StyleInfo)* data->CachedStyleInfo),
              (data->CachedTextLen+3) & 0xfffffffc);
  data->CachedLine=-1;
  return (TRUE);
 }





unsigned int GetLineInfo (struct Class_Data *data,struct LineInfo *linf,
                          unsigned long line)
 {
  struct LineCache *lc;
  signed long oldgarb;

  oldgarb=data->GarbagedLines;
  if (data->CachedLine==line)
   {
    linf->Styles=data->CachedStyle;
    linf->Chars=data->CachedChar;
    linf->StyleLen=data->CachedStyleInfo;
    linf->CharLen=data->CachedTextLen;
    linf->line=line;
    linf->edi=data->DisplayPage;
    return (TRUE);
   }
  lc=GetLineCache(data,line);
  if (lc==NULL) return (FALSE);
  linf->Styles=(void *)lc->LineMemory;
  linf->Chars=lc->LineMemory+(lc->StyleInfos*sizeof(struct StyleInfo));
  linf->StyleLen=lc->StyleInfos;
  linf->CharLen=lc->LineLength;
  linf->line=line-data->GarbagedLines+oldgarb;
  linf->edi=data->DisplayPage;
  return (TRUE);
 }

unsigned int GetLineInfoPg (struct Class_Data *data,unsigned long page,
                            struct LineInfo *linf,unsigned long line)
 {
  struct LineCache *lc;
  struct EditorBuffer *edbuf;
  edbuf=data->Buffers[page];

  if (edbuf->BufferLineCache <= line)
   {
    return (FALSE);
   }
  

  lc=(struct LineCache *) (edbuf->EditorMem+edbuf->BufferSize) - (line+1);
  linf->Styles=(void *)lc->LineMemory;
  linf->Chars=lc->LineMemory+(lc->StyleInfos*sizeof(struct StyleInfo));
  linf->StyleLen=lc->StyleInfos;
  linf->CharLen=lc->LineLength;
  linf->line=line;
  linf->edi=page;
  return (TRUE);
 }

