/*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

#include <libraries/mui.h>
#include <intuition/classes.h>

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


#include <graphics/scale.h>
#include <exec/memory.h>
#include <dos/exall.h>


#include <clib/muimaster_protos.h>
#include <clib/alib_protos.h>
#include <clib/utility_protos.h>
#include <clib/graphics_protos.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/dos_protos.h>


#ifdef __GNUC__


extern void *SysBase;
extern void *IntuitionBase;
extern void *UtilityBase;
extern void *GfxBase;
extern void *KeymapBase;
extern void *MUIMasterBase;

#define NO_INLINE_STDARG

#include <inline/muimaster.h>
#include <inline/exec.h>
#include <inline/intuition.h>
#include <inline/utility.h>
#include <inline/graphics.h>
#include <inline/keymap.h>
#endif

#include <devices/clipboard.h>

struct ImExStruct

  {
   struct Hook *UserHook;
   void        *UserHandle;
   void        *UserObject;
  };



void CompleteRefresh(struct Class_Data *date);

void memcpyfast(void *Source,void *Destination,unsigned long Bytes);

typedef unsigned long (*shookfunc)(void *handle,void *data,unsigned long len);

signed long Save_Stream(struct Class_Data *data,
     shookfunc hookfunc,
     void *streamhandle,unsigned long page,unsigned long mode,
     unsigned long marked);

signed long Load_Stream(struct Class_Data *data,
     shookfunc hookfunc,
     void *streamhandle,unsigned long page,unsigned long mode,
     unsigned long insert);

signed long Load_Stream_GetLine(struct Class_Data *data,
            shookfunc hookfunc,void *streamhandle,unsigned long mode,
            struct EditorBuffer *edbuf,unsigned char *buffermem,
            unsigned long *inbuffer,const unsigned char *convert,
            unsigned char **ffptr);



unsigned long Clipboard_Write( struct IOClipReq *ior,void *charptr,unsigned long datasize);
unsigned long Clipboard_Read( struct IOClipReq *ior,void *charptr,unsigned long datasize);

unsigned long File_Write( BPTR fh,void *charptr,unsigned long datasize);
unsigned long File_Read( BPTR fh,void *charptr,unsigned long datasize);

unsigned long Handle_UserHook( struct ImExStruct *hptr,
                               void *charptr,
                               unsigned long datasize);


extern const unsigned char ConvertAmiga2PC[];
extern const unsigned char ConvertPC2Amiga[];


ULONG _PutStorage(struct IClass *cl,Object *obj, unsigned long *msg)
{
 struct Class_Data *data = INST_DATA(cl, obj);
 BPTR FileSpec;
 unsigned long CurrentPage;
 struct EditorBuffer *edbuf;

 FileSpec= (BPTR) *(msg+1);

 if (CacheClear(data)==FALSE)
  {
   DisplayBeep(NULL);  
  }
 
 /* Write header code */
 {
  unsigned char *xp;
  unsigned long *yp;
  
  xp=data->CachedChar;

  *(xp++)='M';
  *(xp++)='C';
  *(xp++)='C';
  *(xp++)='_';
  *(xp++)='E';
  *(xp++)='D';
  *(xp++)='I';
  *(xp++)='T';
  yp=(unsigned long *) xp;
  *(yp++)=1;
  *(yp++)=data->Pages;

  if (Write(FileSpec,data->CachedChar,16)!=16)
   {
    return (MUIV_Editor_Return_Disk_DiskError);
   }
 }

 for (CurrentPage=0;CurrentPage<data->Pages;++CurrentPage)
  {
   edbuf=data->Buffers[CurrentPage];
   /* write page header code + editor buffer*/
    {
     unsigned long *xp;
     unsigned long xl;
     xp=(unsigned long *) data->CachedChar;
     *(xp++)=edbuf->BufferFilled;
     *(xp++)=edbuf->BufferLineCache;
     *(xp++)=sizeof(struct EditorBuffer);
     memcpyfast (edbuf,xp,sizeof(struct EditorBuffer));
     xl=12+sizeof(struct EditorBuffer);
     if (Write(FileSpec,data->CachedChar,xl)!=xl)
      {
       return (MUIV_Editor_Return_Disk_DiskError);
      }

    }
   
   /* write chars through cache */
    {
     unsigned long restchars;
     unsigned char *restptr;
     unsigned long jobchars;
     restchars=edbuf->BufferFilled;
     restptr=edbuf->EditorMem;
     while (restchars>0)
      {
       jobchars= (restchars>4096)?4096:restchars;

       memcpyfast(restptr,data->CachedChar,jobchars);

       restptr+=jobchars;
       restchars-=jobchars;

       if ( Write(FileSpec,data->CachedChar,jobchars)!=jobchars)
        { 
         return (MUIV_Editor_Return_Disk_DiskError);
        }
      }
    }
   /* write shortened line caches */
    {
     unsigned long restlines,joblines;
     struct LineCache *restptr; 
     restlines=edbuf->BufferLineCache;
     restptr=(struct LineCache *) (edbuf->EditorMem+edbuf->BufferSize);
     while (restlines>0)
      {
       unsigned long i;
       unsigned short *jobptr;
       joblines=(restlines>512)?512:restlines;
       jobptr=(unsigned short *) data->CachedChar;
       for (i=0;i<joblines;++i)
        {
         --restptr;
         *(jobptr++)=(restptr->LineLength);
         *(jobptr++)=(restptr->StyleInfos);
        }
       if ( Write(FileSpec,data->CachedChar,joblines*4)!=joblines*4)
        { 
         return (MUIV_Editor_Return_Disk_DiskError);
        }
       restlines-=joblines;
      }
    }
  }

 return (MUIV_Editor_Return_OK);
}

ULONG _GetStorage(struct IClass *cl,Object *obj, unsigned long *msg)
{
 struct Class_Data *data = INST_DATA(cl, obj);

 BPTR FileSpec;
 unsigned long CurrentPage;
 unsigned long FilePages;
 unsigned long error;
 struct EditorBuffer *edbuf;


 error=MUIV_Editor_Return_OK;

 FileSpec= (BPTR) *(msg+1);

 CacheClear(data);

  {
   /* Clear all buffers */
   unsigned long i;
   for (i=0;i<data->Pages;++i)
    {
     ClearBuffer(data->Buffers[i]);
    }
   CompleteRefresh(data);   
  }
  
  {
   /* Read header */
   unsigned char *xp;
   unsigned long *yp;
   if ( Read(FileSpec,data->CachedChar,16)!=16) 
    {
     MUI_Redraw (obj,MADF_DRAWUPDATE);
     return (MUIV_Editor_Return_Disk_DiskError); 
    }
   xp=data->CachedChar;
   if ( 
       (*(xp++)!='M') ||
       (*(xp++)!='C') ||
       (*(xp++)!='C') ||
       (*(xp++)!='_') ||
       (*(xp++)!='E') ||
       (*(xp++)!='D') ||
       (*(xp++)!='I') ||
       (*(xp++)!='T') 
      ) 
    {
     MUI_Redraw (obj,MADF_DRAWUPDATE);
     return (MUIV_Editor_Return_Disk_UnknownFileForm); 
    }
   yp=(unsigned long *) xp;
   if ( *(yp++) != 1 )
    {
     MUI_Redraw (obj,MADF_DRAWUPDATE);
     return (MUIV_Editor_Return_Disk_UnknownFileForm); 
    }
   FilePages=*(yp);
  }
 for (CurrentPage=0;CurrentPage<FilePages;++CurrentPage)
  {
   unsigned long TableBytes[3];
   
   if ( Read(FileSpec,TableBytes,12)!=12) 
     {
      error=MUIV_Editor_Return_Disk_DiskError;
      break;
     }

   if (
       (TableBytes[2]!=sizeof(struct EditorBuffer)) ||
       (CurrentPage>=data->Pages) ||
       ( (TableBytes[0]+TableBytes[1]*sizeof(struct LineCache) ) 
         > (data->Buffers[CurrentPage])->BufferSize)
       )
    {
     if ( (CurrentPage>=data->Pages) && 
          (TableBytes[2]==sizeof(struct EditorBuffer)))
       error=MUIV_Editor_Return_Disk_BuffersTooSmall;
       break;

     if ( Seek(FileSpec,TableBytes[0]+TableBytes[1]*4+TableBytes[2],0)==-1)
      {
       error=MUIV_Editor_Return_Disk_DiskError;
       break;
      }
     continue;
    }

   edbuf=data->Buffers[CurrentPage];
   if (Read(FileSpec,data->CachedChar,TableBytes[2])!=TableBytes[2])
    {
     error=MUIV_Editor_Return_Disk_DiskError;
     break;
    }
    {
     struct EditorBuffer *newed;
     newed=(struct EditorBuffer *) data->CachedChar;
     newed->BufferSize=edbuf->BufferSize;
     newed->EditorMem=edbuf->EditorMem;
     if (newed->BufferFilled!=TableBytes[0])
      {
       error=MUIV_Editor_Return_Disk_FileCorrupt;
       break;       
      }
     if (newed->BufferLineCache!=TableBytes[1])
      {
       error=MUIV_Editor_Return_Disk_FileCorrupt;
       break;       
      }
     memcpyfast(newed,edbuf,sizeof (struct EditorBuffer) );
    }


   /* read chars through cache */
    {
     unsigned long restchars;
     unsigned char *restptr;
     unsigned long jobchars;
     restchars=edbuf->BufferFilled;
     restptr=edbuf->EditorMem;
     while (restchars>0)
      {
       jobchars= (restchars>4096)?4096:restchars;

       if ( Read(FileSpec,data->CachedChar,jobchars)!=jobchars)
        { 
         ClearBuffer(edbuf);
         error=MUIV_Editor_Return_Disk_DiskError;
         break;
        }

       memcpyfast(data->CachedChar,restptr,jobchars);

       restptr+=jobchars;
       restchars-=jobchars;

      }
    }

   if (error==MUIV_Editor_Return_Disk_DiskError) break;


   /* read shortened line caches */
    {
     unsigned long restlines,joblines;
     struct LineCache *restptr; 
     restlines=edbuf->BufferLineCache;
     restptr=(struct LineCache *) (edbuf->EditorMem+edbuf->BufferSize);
     while (restlines>0)
      {
       unsigned long i;
       unsigned short *jobptr;
       joblines=(restlines>512)?512:restlines;

       if ( Read(FileSpec,data->CachedChar,joblines*4)!=joblines*4)
        { 
         ClearBuffer(edbuf);
         error=MUIV_Editor_Return_Disk_DiskError;
         break;
        }


       jobptr=(unsigned short *) data->CachedChar;
       for (i=0;i<joblines;++i)
        {
         --restptr;
         (restptr->LineLength)=*(jobptr++);
         (restptr->StyleInfos)=*(jobptr++);
        }
       restlines-=joblines;
      }
    }

   if (error==MUIV_Editor_Return_Disk_DiskError) break;


   /* relocate memory - test integrity */
   {
    struct LineCache *lcp;
    unsigned char *mp;
    unsigned long filledby,onefill;
    unsigned long i;
    filledby=0;
    lcp=(struct LineCache *) (edbuf->EditorMem+edbuf->BufferSize);
    mp=edbuf->EditorMem;
    for (i=0;i<edbuf->BufferLineCache;++i)
     {
      lcp--;
      if ( 
          (lcp->LineLength>4096) ||
          (lcp->StyleInfos>128) ||
          (lcp->StyleInfos==0) )
       {
        ClearBuffer(edbuf); 
        error=MUIV_Editor_Return_Disk_FileCorrupt;
        break;
       }
      onefill=(lcp->LineLength+3) & 0xfffffffc;
      onefill+=sizeof(struct StyleInfo) * lcp->StyleInfos;
      filledby+=onefill;
      lcp->LineMemory=mp;
      mp+=onefill;
     }
    if (error==MUIV_Editor_Return_Disk_FileCorrupt) break;
    if (filledby!=edbuf->BufferFilled)
     {
      ClearBuffer(edbuf); 
      error=MUIV_Editor_Return_Disk_FileCorrupt;
      break;
     }
   }
      
  }
 MUI_Redraw (obj,MADF_DRAWUPDATE);
 return (error);
}

ULONG _ExportPage(struct IClass *cl,Object *obj, unsigned long *msg)
{
 struct Class_Data *data = INST_DATA(cl, obj);
 BPTR file;
 unsigned long page;
 unsigned long mode;
 unsigned long marked;
 struct EditorBuffer *edbuf;
 unsigned long volatile gump;
 
 file=(BPTR) *(msg+1);
 page=*(msg+2);
 mode=*(msg+3);
 marked=*(msg+4);
 
 if ( (page<0) || (page>=data->Pages) )
  {
   return (MUIV_Editor_Return_InvalidPage);
  }


 if ( file==0)
  {
   return (MUIV_Editor_Return_Disk_DiskError);  
  }

 edbuf=data->Buffers[page];
 
 gump=mode & ( MUIV_Editor_ImExMode_LF | MUIV_Editor_ImExMode_CR | MUIV_Editor_ImExMode_CRLF);
 

 if ( gump == 0)
  {
   mode|=
    (edbuf->ImportMode & 
     ( MUIV_Editor_ImExMode_LF | MUIV_Editor_ImExMode_CR | MUIV_Editor_ImExMode_CRLF   )
    );
  }

 gump=mode & ( MUIV_Editor_ImExMode_AmChar | MUIV_Editor_ImExMode_PCChar);
 

 if (gump== 0)
  {
   mode|=
    (edbuf->ImportMode &
     ( MUIV_Editor_ImExMode_AmChar | MUIV_Editor_ImExMode_PCChar)
    );
  }

 return(Save_Stream(data,(shookfunc) File_Write,(void *) file,page,mode,marked));
}

ULONG _ImportPage(struct IClass *cl,Object *obj, unsigned long *msg)
{
 struct Class_Data *data = INST_DATA(cl, obj);
 BPTR file;
 unsigned long page;
 unsigned long mode;

 file=(BPTR) *(msg+1);
 page=*(msg+2);
 mode=*(msg+3);
 
 if ( (page<0) || (page>=data->Pages) )
  {
   return (MUIV_Editor_Return_InvalidPage);
  }

 if ( file==0)
  {
   return (MUIV_Editor_Return_Disk_DiskError);  
  }
 
 return(Load_Stream(data,(shookfunc) File_Read,(void *) file,page,mode,FALSE));
}



ULONG _ExportStream(struct IClass *cl,Object *obj, unsigned long *msg)
{
 struct Class_Data *data = INST_DATA(cl, obj);
 unsigned long page;
 unsigned long mode;
 unsigned long marked;
 struct EditorBuffer *edbuf;
 struct ImExStruct userstruct;
 unsigned long volatile gump;

 page=*(msg+2);
 mode=*(msg+3);
 marked=*(msg+4);

 userstruct.UserHandle=(void *) *(msg+1);
 userstruct.UserHook=(void *) *(msg+5);
 userstruct.UserObject=(void *) obj;

 if ( (page<0) || (page>=data->Pages) )
  {
   return (MUIV_Editor_Return_InvalidPage);
  }

 edbuf=data->Buffers[page];

 gump=mode & ( MUIV_Editor_ImExMode_LF | MUIV_Editor_ImExMode_CR | MUIV_Editor_ImExMode_CRLF);
 

 if ( gump == 0)
  {
   mode|=
    (edbuf->ImportMode & 
     ( MUIV_Editor_ImExMode_LF | MUIV_Editor_ImExMode_CR | MUIV_Editor_ImExMode_CRLF   )
    );
  }

 gump=mode & ( MUIV_Editor_ImExMode_AmChar | MUIV_Editor_ImExMode_PCChar);
 

 if (gump== 0)
  {
   mode|=
    (edbuf->ImportMode &
     ( MUIV_Editor_ImExMode_AmChar | MUIV_Editor_ImExMode_PCChar)
    );
  }
 
 
 return(Save_Stream(data,(shookfunc) Handle_UserHook,(void *) &userstruct,page,mode,marked));
}

ULONG _ImportStream(struct IClass *cl,Object *obj, unsigned long *msg)
{
 struct Class_Data *data = INST_DATA(cl, obj);
 unsigned long page;
 unsigned long mode;
 struct ImExStruct userstruct;

 userstruct.UserHandle=(void *) *(msg+1);
 userstruct.UserHook=(void *) *(msg+4);
 userstruct.UserObject=obj;

 page=*(msg+2);
 mode=*(msg+3);

 if ( (page<0) || (page>=data->Pages) )
  {
   return (MUIV_Editor_Return_InvalidPage);
  }

 return(Load_Stream(data,(shookfunc) Handle_UserHook,(void *)&userstruct,page,mode,FALSE));
}


unsigned long Handle_UserHook( struct ImExStruct *hptr,
                               void *charptr,
                               unsigned long datasize)
{
 return (CallHook(hptr->UserHook,(Object *) hptr->UserObject,
         hptr->UserHandle,charptr,datasize));
}


ULONG _ClearPage(struct IClass *cl,Object *obj, unsigned long *msg)
{
 struct Class_Data *data = INST_DATA(cl, obj);
 unsigned long page;

 page=*(msg+1);
 if ( (page<0) || (page>=data->Pages) ) return (MUIV_Editor_Return_InvalidPage);
 ClearBuffer(data->Buffers[page]);

 if (page==data->DisplayPage)
  {
   CompleteRefresh(data);
   MUI_Redraw (obj,MADF_DRAWUPDATE);
  }
 
 return (MUIV_Editor_Return_OK);
}



ULONG _ANSIToStream(struct IClass *cl,Object *obj, unsigned long *msg)
{
 /*struct Class_Data *data = INST_DATA(cl, obj);   */
 return ( Stream_ANSIToStream( (void *) *(msg+1)));
}

ULONG _StreamToANSI(struct IClass *cl,Object *obj, unsigned long *msg)
{
 /*struct Class_Data *data = INST_DATA(cl, obj); */
 return ( Stream_StreamToANSI( (void *) *(msg+1)));
}


ULONG _WriteANSI(struct IClass *cl,Object *obj, unsigned long *msg)
{
 struct Class_Data *data = INST_DATA(cl, obj);
 unsigned long page;
 unsigned char *charptr;
 unsigned long charlen;
 struct ANSIJob *myjob,*conjob;


 if ( (data->Type==0) && (data->Interactive==FALSE) )
  {
   return (MUIV_Editor_Return_Write_NotInteractive); 
  }

 page=*(msg+1);
 charptr=(void *)  *(msg+2);
 charlen=*(msg+3);

 if (page>=data->Pages)
  {
   return (MUIV_Editor_Return_Write_IllegalPage);
  }

 if ( (myjob=AllocVec(sizeof(struct ANSIJob)+charlen,1))==FALSE)
  {
   return (MUIV_Editor_Return_Write_NoMemory);
  } 
 
 myjob->next=NULL;
 myjob->inserttype=FALSE;
 myjob->page=page;
 myjob->charsize=charlen;
 myjob->charptr=(void *) (myjob+1 );
 myjob->styles=NULL;
 myjob->stylesize=0;
 myjob->streamcr=0;
 CopyMem(charptr,myjob->charptr,charlen);

 conjob=(void *) &(data->JobStack ) ;
 while (conjob->next!=NULL)
  { 
   conjob=conjob->next;
  }
 conjob->next=myjob;
  {
   struct EditorBuffer *edbuf;
   
   edbuf=data->Buffers[page];
   if (edbuf->InputLine==-1)
    {
     Handle_Jobs(data);
    }
  }

 if (data->Refresh!=0)
   {
    MUI_Redraw (obj,MADF_DRAWUPDATE);
   }

 return (MUIV_Editor_Return_OK);
}

ULONG _WriteStream(struct IClass *cl,Object *obj, unsigned long *msg)
{
 struct Class_Data *data = INST_DATA(cl, obj);

 unsigned long page;
 unsigned char *charptr;
 struct StyleInfos *styles;
 unsigned long charlen,stylelen,streamcr;
 struct ANSIJob *myjob,*conjob;
 

 if ( (data->Type==0) && (data->Interactive==FALSE) )
  {
   return (MUIV_Editor_Return_Write_NotInteractive); 
  }

 page=*(msg+1);
 charptr=(void *)  *(msg+2);
 charlen=*(msg+3);
 styles=(void *) *(msg+4);
 stylelen=*(msg+5);
 streamcr=*(msg+6);

 if (page>=data->Pages)
  {
   return (MUIV_Editor_Return_Write_IllegalPage);
  }

 if ( (myjob=AllocVec(sizeof(struct ANSIJob)+charlen+
        sizeof(struct StyleInfo)*stylelen,1))==FALSE)
  {
   return (MUIV_Editor_Return_Write_NoMemory);
  } 
 
 myjob->next=NULL;
 myjob->inserttype=TRUE;
 myjob->page=page;
 myjob->charsize=charlen;
 myjob->charptr=(unsigned char *) (myjob+1 )+stylelen*sizeof(struct StyleInfo);
 myjob->styles=(struct StyleInfo *) (myjob+1);
 myjob->stylesize=stylelen;
 myjob->streamcr=streamcr;
 
 CopyMem(charptr,myjob->charptr,charlen);
 CopyMem(styles,myjob->styles,stylelen*sizeof(struct StyleInfo));

 conjob=(void *) &(data->JobStack ); 
 while (conjob->next!=NULL)
  { 
   conjob=conjob->next;
  }
 conjob->next=myjob;
  {
   struct EditorBuffer *edbuf;
   
   edbuf=data->Buffers[page];
   if (edbuf->InputLine==-1)
    {
     Handle_Jobs(data);
    }
  }

 if (data->Refresh!=0)
   {
    MUI_Redraw (obj,MADF_DRAWUPDATE);
   }



 return (MUIV_Editor_Return_OK);

}



void Handle_Jobs(struct Class_Data *data)
{
 struct ANSIJob *prejob,*currentjob;
 struct EditorBuffer *edbuf;
 
 unsigned long savepage;


 prejob=(void *) &(data->JobStack ) ;
 
 while (prejob->next!=NULL)
  {
   unsigned short thispage,savevalid; 
   unsigned short CursorFollow=FALSE;
   currentjob=prejob->next;
   edbuf=data->Buffers[currentjob->page];
   if (edbuf->InputLine!=-1) 
    {
     prejob=prejob->next;
     continue;
    }
   prejob->next=currentjob->next;
 
   if (CacheClear(data)==FALSE)
    {
     DisplayBeep(NULL);
    }

   /* Handle job*/

   thispage=FALSE;
   savepage=data->DisplayPage;
   savevalid=data->ValidDisplay;
   data->DisplayPage=currentjob->page;
   if (savepage==currentjob->page) thispage=TRUE;
   if (thispage==FALSE) data->ValidDisplay=FALSE;
   if ( (savevalid==FALSE) || ( (edbuf->HeadLine+data->GfxLines)
         >edbuf->CursorLine) ) 
    {
     CursorFollow=TRUE;
    }

   if ((thispage==TRUE) && (data->Refresh==0)) data->Refresh=1;


   if (currentjob->inserttype==FALSE)
    {
     /* Insert ANSI type */
     unsigned char *ansiptr,*thisptr;
     unsigned long ansilen;
     unsigned long thislen;
     unsigned short firststyler;
     
     firststyler=TRUE;
     ansiptr=currentjob->charptr;
     ansilen=currentjob->charsize;
     
     while (ansilen!=0)
      {
       if (CacheSet(data,edbuf->CursorLine)==FALSE)
        {
         DisplayBeep(NULL);
         break;
        }
       thislen=0;
       thisptr=ansiptr;
       while  ( ( *(thisptr)!='\012' ) && (thislen<ansilen) )
        {
         thisptr++;
         thislen++;
        }
       edbuf->ANSIInput.StreamCR=FALSE;
       if ( (thislen<ansilen) && (*(thisptr)=='\012') )
        {
         thislen++;
        }

       if (firststyler==TRUE)
        {
         struct StyleInfo *laststyle;
         firststyler=FALSE;
         laststyle=data->CachedStyle+data->CachedStyleInfo-1;         
         edbuf->ANSIInput.ForegroundColor=laststyle->ForegroundColor;
         edbuf->ANSIInput.BackgroundColor=laststyle->BackgroundColor;
         edbuf->ANSIInput.TextStyle=laststyle->TextStyle;
        }
        
       data->CachedTextLen=edbuf->CursorColumn;       

       while (data->CachedStyleInfo!=0)      
        {
         struct StyleInfo *laststyle;
         laststyle=data->CachedStyle+data->CachedStyleInfo-1;         
         if (laststyle->StartColumn>=data->CachedTextLen)
          {
           data->CachedStyleInfo--;
           continue;
          }
         break;
        }


       edbuf->ANSIInput.TextBuffer=ansiptr;
       edbuf->ANSIInput.TextBufferSize=thislen;
       edbuf->ANSIInput.TextLength=thislen;
       edbuf->ANSIInput.CharBuffer=data->CachedChar+data->CachedTextLen;
       edbuf->ANSIInput.CharBufferSize=4096-data->CachedTextLen;
       edbuf->ANSIInput.Styles=data->CachedStyle+data->CachedStyleInfo;
       edbuf->ANSIInput.StyleSize=128-data->CachedStyleInfo;
       edbuf->ANSIInput.CurrentColumn=data->CachedTextLen;

 
       if ( (thispage==TRUE) && (data->ValidDisplay!=FALSE) && (edbuf->HeadLine<=edbuf->CursorLine))
        {
         unsigned long ix;
         ix=edbuf->CursorLine-edbuf->HeadLine;
         if ( (ix<data->GfxLines) && 
              ( (data->RefreshLine[ix]==-1) || (data->RefreshLine[ix]>
                 data->CachedTextLen) ) )
          {
           data->RefreshLine[ix]=data->CachedTextLen;
          }
        }

       if (Stream_ANSIToStream(&edbuf->ANSIInput)!=MUIV_Editor_Return_OK)
        {
         DisplayBeep(NULL);
        }
       
       data->CachedStyleInfo+=edbuf->ANSIInput.UsedStyles;
       data->CachedTextLen+=edbuf->ANSIInput.CharLength;
       edbuf->CursorColumn=data->CachedTextLen;
       
       ansilen-=thislen;
       ansiptr+=thislen;
       if (CacheClear(data)==FALSE)
        {
         edbuf->CursorColumn=0;
         edbuf->CursorLine=edbuf->BufferLineCache-1;
         DisplayBeep(NULL);
         break;
        }

       if (edbuf->ANSIInput.StreamCR==TRUE)
        {
         if (edbuf->CursorLine+1==data->MaxLines)
          {
           break;
          }
          else
          {
           struct LineInfo linf;
           if ( GetLineInfo(data,&linf,edbuf->CursorLine+1) ==FALSE)
             {
              edbuf->CursorColumn=0;
              edbuf->CursorLine=edbuf->BufferLineCache-1;
              DisplayBeep(NULL);
              break;
             }
             else    
             {
              edbuf->CursorColumn=0;
              edbuf->CursorLine++;
             }
          }
        }

        
      }
     
    }
    else
    {
     /* Insert stream type */

     if (CacheSet(data,edbuf->CursorLine)==FALSE)
       {
        DisplayBeep(NULL);
        break;
       }

     data->CachedTextLen=edbuf->CursorColumn;

     while (data->CachedStyleInfo!=0)      
      {
       struct StyleInfo *laststyle;
       laststyle=data->CachedStyle+data->CachedStyleInfo-1;         
       if (laststyle->StartColumn>data->CachedTextLen)
        {
         data->CachedStyleInfo--;
         continue;
        }
       break;
      }

     if ( (thispage==TRUE) && (data->ValidDisplay!=FALSE) && (edbuf->HeadLine<=edbuf->CursorLine))
      {
       unsigned long ix;
       ix=edbuf->CursorLine-edbuf->HeadLine;
       if ( (ix<data->GfxLines) && 
            ( (data->RefreshLine[ix]==-1) || (data->RefreshLine[ix]>
               data->CachedTextLen) ) )
        {
         data->RefreshLine[ix]=data->CachedTextLen;
        }
      }


      {
       unsigned char *insertchar; 
       struct StyleInfo *insertstyle;
       unsigned long insertcharl;
       unsigned long insertstylel;
       unsigned char *placeptr;
       struct StyleInfo *styleplaceptr;

       insertchar=currentjob->charptr;
       insertstyle=currentjob->styles;
       insertcharl=currentjob->charsize;
       insertstylel=currentjob->stylesize;
      
       placeptr=&data->CachedChar[data->CachedTextLen];
       styleplaceptr=data->CachedStyle+data->CachedStyleInfo;
         
       if ( (data->CachedStyleInfo!=0) && (insertstylel!=0) )
        {
         struct StyleInfo *laststyle;
         laststyle=styleplaceptr-1;
         if ( (insertstyle->ForegroundColor==laststyle->ForegroundColor) &&
              (insertstyle->BackgroundColor==laststyle->BackgroundColor) &&
              (insertstyle->TextStyle==laststyle->TextStyle) )
          {
           insertstyle++;
           insertstylel--;
          }
        }
       
       if ( (data->CachedStyleInfo!=0) && (insertstylel!=0) && (insertstyle->StartColumn==0))
        {
         if ((styleplaceptr-1)->StartColumn==edbuf->CursorColumn)
          {
           styleplaceptr--;
           data->CachedStyleInfo--;
          }
        }
     
       while (insertstylel!=0)
        {
         *(styleplaceptr)=*(insertstyle++);
         --insertstylel;
         styleplaceptr->StartColumn+=edbuf->CursorColumn;
         ++styleplaceptr;
         ++data->CachedStyleInfo;
        }

       while (insertcharl!=0)
        {
         *(placeptr++)=*(insertchar++);
         --insertcharl;
         ++data->CachedTextLen;
        }
      }

     edbuf->CursorColumn=data->CachedTextLen;
       
     if (CacheClear(data)==FALSE)
      {
       edbuf->CursorColumn=0;
       edbuf->CursorLine=edbuf->BufferLineCache-1;
       DisplayBeep(NULL);
       break;
      }

     if (currentjob->streamcr==TRUE)
      {
       if (edbuf->CursorLine+1==data->MaxLines)
        {
         break;
        }
        else
        {
         struct LineInfo linf;
         if ( GetLineInfo(data,&linf,edbuf->CursorLine+1) ==FALSE)
           {
            edbuf->CursorColumn=0;
            edbuf->CursorLine=edbuf->BufferLineCache-1;
            DisplayBeep(NULL);
            break;
           }    
           else
           {
            edbuf->CursorColumn=0;
            edbuf->CursorLine++;
           }
        }
      }

 
    }

   if (CursorFollow==TRUE)
    {
     if (savevalid==FALSE)
      {
       edbuf->HeadLine=edbuf->CursorLine;
       edbuf->HeadColumn=0;
      }
      else
      {
       if ((edbuf->HeadLine+data->GfxLines)<=edbuf->CursorLine)
        {
         if (thispage!=FALSE) ScrollEditor(data,edbuf->HeadLine-(edbuf->CursorLine-data->GfxLines+1));
         edbuf->HeadLine=edbuf->CursorLine-data->GfxLines+1;
        }
      }
    }
   data->DisplayPage=savepage;   
   data->ValidDisplay=savevalid;
   FreeVec(currentjob);
  } 
 
}

void Put_InputStream(struct Class_Data *data)
{
 unsigned long offi,startcol,i;
 struct EditorBuffer *edbuf;
 struct LineInfo linf;
 struct StyleInfo *xstyle,*ystyle;
 unsigned char *xchar,*ychar;
 unsigned long xstylel,xcharl;

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


 while ( (edbuf->InputLine!=-1) && ( (edbuf->InputLine+offi) <= edbuf->CursorLine ) )
  {
   if ( GetLineInfo(data,&linf,edbuf->InputLine+offi) ==FALSE)
    {
     return;
    }
   xchar=linf.Chars;
   xcharl=linf.CharLen;
   xstyle=linf.Styles;
   xstylel=linf.StyleLen;
   startcol=0;
   if (offi!=0)
    {
     startcol=edbuf->InputColumn;
     while ( (xstylel>1) && ((xstyle+1)->StartColumn<startcol) )
      {
       xstylel--; 
       xstyle++;
      }
     xchar+=startcol;
     xcharl-=startcol;
    }
   ychar=data->CachedChar;
   ystyle=data->CachedStyle;
   for (i=0;i<xcharl;++i)
    {
     *(ychar++)=*(xchar++);
    }
   for (i=0;i<xstylel;++i)
    {
     *(ystyle++)=*(xstyle++);
     if (ystyle->StartColumn<=startcol)
      {
       ystyle->StartColumn=0;
      }
      else
      {
       ystyle->StartColumn-=startcol;
      }
    }
    {
     unsigned long xarray[5];
     xarray[0]=(unsigned long) data->CachedChar;
     xarray[1]=xcharl;
     xarray[2]=(unsigned long) data->CachedStyle;
     xarray[3]=xstylel;
     xarray[4]=TRUE;
     SetAttrs(data->RootObject,MUIA_Editor_NotifyStream,(ULONG) xarray,TAG_DONE);
    }
   offi++; 
  }
}

void Put_InputANSI(struct Class_Data *data)
{
 unsigned long offi;
 struct EditorBuffer *edbuf;
 struct LineInfo linf;
 struct ANSIStream ansi;

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

 /* Get info of previous line */ 

 if (edbuf->InputLine<=0)
  {
   ansi.ForegroundColor=1;
   ansi.BackgroundColor=0;
   ansi.TextStyle=0;
  }
  else
  {
   struct StyleInfo *style;
   if ( GetLineInfo(data,&linf,edbuf->InputLine-1) ==FALSE) return;
   style=linf.Styles+linf.StyleLen-1;
   ansi.ForegroundColor=style->ForegroundColor;
   ansi.BackgroundColor=style->BackgroundColor;
   ansi.TextStyle=style->TextStyle;  
  }
 ansi.Pad1=0;
 ansi.ANSICmdState=0;

 while ( (edbuf->InputLine!=-1) && ( (edbuf->InputLine+offi) <= edbuf->CursorLine ) )
  {
   if ( GetLineInfo(data,&linf,edbuf->InputLine+offi) ==FALSE)
    {
     return;
    }
   ansi.CharBuffer=linf.Chars;
   ansi.CharLength=linf.CharLen;
   ansi.Styles=linf.Styles;
   ansi.UsedStyles=linf.StyleLen;
   ansi.CurrentColumn=0;
   ansi.StreamCR=TRUE;
   if ( (offi==0) && (edbuf->InputColumn>0) )
    {
     struct StyleInfo *xstyle;
     signed long ystyle;
     ansi.CurrentColumn=edbuf->InputColumn;
     xstyle=ansi.Styles;
     ystyle=ansi.UsedStyles;
     while (ystyle>0)
      {
       if (xstyle->StartColumn>=ansi.CurrentColumn) break;
       ansi.ForegroundColor=xstyle->ForegroundColor;
       ansi.BackgroundColor=xstyle->BackgroundColor;
       ansi.TextStyle=xstyle->TextStyle;
       xstyle++;
       ystyle--;
      }
    }
   while (1)
    {
     signed long ret;
     ansi.TextBuffer=data->CachedChar;
     ansi.TextBufferSize=4096;
     
     ret=Stream_StreamToANSI(&ansi);
     if ( (ret!=MUIV_Editor_Return_ANSI_NotFinished) &&
          (ret!=MUIV_Editor_Return_OK) )return;
     {
      unsigned long xarray[2];
      xarray[0]=(unsigned long) data->CachedChar;
      xarray[1]=ansi.TextLength;
      SetAttrs(data->RootObject,MUIA_Editor_NotifyANSI,(ULONG) xarray,TAG_DONE);
      if (ret==MUIV_Editor_Return_OK) break;
     }
     
    }       
   offi++;
  }
}


void ClipboardCopy(struct Class_Data *data)
{
 struct MsgPort *msg;
 struct IOClipReq *iclip;
 signed long error;
 msg=CreateMsgPort();
 if (msg==NULL) 
  {
   DisplayBeep(NULL);
   return;
  }
 iclip=(struct IOClipReq *) CreateIORequest(msg,sizeof(*iclip));
 if (iclip==NULL)
  {
   DeleteMsgPort(msg);
   DisplayBeep(NULL);
   return;
  }
 if ( OpenDevice("clipboard.device",0,(struct IORequest *) iclip,0)!=0)
  {
   DeleteIORequest((struct IORequest *)iclip);
   DeleteMsgPort(msg);
   DisplayBeep(NULL);
   return;
  }

 iclip->io_Offset=0;
 iclip->io_ClipID=0;
 
  {
   unsigned long header[5];
   header[0]=0x464f524d;
   header[1]=0x00000000;
   header[2]=0x46545854;
   header[3]=0x43485253;
   header[4]=0x00000000;
   iclip->io_Data=(void *) header;
   iclip->io_Length=20;
   iclip->io_Offset=0;
   iclip->io_Command=CMD_WRITE;
   DoIO((struct IORequest *) iclip);   
  }

 if (iclip->io_Error!=0)
  {
   CloseDevice((struct IORequest *) iclip);
   DeleteIORequest((struct IORequest *) iclip);
   DeleteMsgPort(msg);
   DisplayBeep(NULL);
   return;
  }

 error=Save_Stream(data,(shookfunc) Clipboard_Write,iclip,data->DisplayPage,
                   MUIV_Editor_ImExMode_AmChar|MUIV_Editor_ImExMode_LF,TRUE);

 if (error==0)
  {
   unsigned long charlen,formlen; 
   charlen=iclip->io_Offset-20;
   formlen=iclip->io_Offset-8;
   if (charlen&1)
    {
     unsigned char dummy;
     ++formlen;
     dummy=0;
     iclip->io_Data=&dummy;
     iclip->io_Length=1;
     iclip->io_Command=CMD_WRITE;
     DoIO((struct IORequest *) iclip);   
     if (iclip->io_Error!=0)
      {
       CloseDevice((struct IORequest *) iclip);
       DeleteIORequest((struct IORequest *) iclip);
       DeleteMsgPort(msg);
       DisplayBeep(NULL);
       return;
      }
    }
    {
     iclip->io_Data=(void *) &charlen;
     iclip->io_Length=4;
     iclip->io_Offset=16;

     iclip->io_Command=CMD_WRITE;
     DoIO((struct IORequest *) iclip);   
     if (iclip->io_Error!=0)
      {
       CloseDevice((struct IORequest *) iclip);
       DeleteIORequest((struct IORequest *) iclip);
       DeleteMsgPort(msg);
       DisplayBeep(NULL);
       return;
      }

    }   
    {
     iclip->io_Data=(void *) &formlen;
     iclip->io_Length=4;
     iclip->io_Offset=4;
     iclip->io_Command=CMD_WRITE;
     DoIO((struct IORequest *) iclip);   
     if (iclip->io_Error!=0)
      {
       CloseDevice((struct IORequest *) iclip);
       DeleteIORequest((struct IORequest *) iclip);
       DeleteMsgPort(msg);
       DisplayBeep(NULL);
       return;
      }

    }   
   
  }
 iclip->io_Command=CMD_UPDATE;
 DoIO((struct IORequest *) iclip);
 CloseDevice((struct IORequest *) iclip);
 DeleteIORequest((struct IORequest *) iclip);
 DeleteMsgPort(msg);
}



void ClipboardPaste(struct Class_Data *data)
{
 struct MsgPort *msg;
 struct IOClipReq *iclip;
 msg=CreateMsgPort();
 if (msg==NULL) 
  {
   DisplayBeep(NULL);
   return;
  }
 iclip=(struct IOClipReq *) CreateIORequest(msg,sizeof(*iclip));
 if (iclip==NULL)
  {
   DeleteMsgPort(msg);
   DisplayBeep(NULL);
   return;
  }
 if ( OpenDevice("clipboard.device",0,(struct IORequest *) iclip,0)!=0)
  {
   DeleteIORequest((struct IORequest *)iclip);
   DeleteMsgPort(msg);
   DisplayBeep(NULL);
   return;
  }

 iclip->io_Offset=0;
 iclip->io_ClipID=0;

  

  {
   unsigned long dummy;
   iclip->io_Data=(void *) &dummy;
   iclip->io_Length=0;
   iclip->io_Offset=1000000000;
   iclip->io_Command=CMD_READ;
   DoIO((struct IORequest *) iclip);
  }
 CloseDevice((struct IORequest *) iclip);
 DeleteIORequest((struct IORequest *) iclip);
 DeleteMsgPort(msg);

}


unsigned long Clipboard_Write( struct IOClipReq *ior,
                               void *charptr,
                               unsigned long datasize)
{
 ior->io_Data=charptr;
 ior->io_Length=datasize;
 ior->io_Command=CMD_WRITE;
 DoIO((struct IORequest *) ior);
 if (ior->io_Error!=0) return (-1);
 return (ior->io_Actual);
}

unsigned long Clipboard_Read(  struct IOClipReq *ior,
                               void *charptr,
                               unsigned long datasize)
{
 ior->io_Data=charptr;
 ior->io_Length=datasize;
 ior->io_Command=CMD_READ;
 DoIO((struct IORequest *) ior);
 if (ior->io_Error!=0) return (-1);
 return (ior->io_Actual);
}

unsigned long File_Write( BPTR fh,
                               void *charptr,
                               unsigned long datasize)
{
 signed long rl;
 rl=Write(fh,charptr,datasize);
 if (rl==-1) return (-1);
 return (rl);
}

unsigned long File_Read(  BPTR fh,
                               void *charptr,
                               unsigned long datasize)
{
 signed long rl;
 rl=Read(fh,charptr,datasize);
 if (rl==-1) return (-1);
 return (rl);
}





signed long Save_Stream(struct Class_Data *data,shookfunc hookfunc,
     void *streamhandle,unsigned long page,unsigned long mode,
     unsigned long marked)
{
 unsigned char *buffermem;
 unsigned long cx,cy,ex,ey;
 struct EditorBuffer *edbuf;
 struct LineInfo linf;
 struct ANSIStream ansi;

 unsigned long inbuffer;
 signed long getbf;
 signed long ansiret;
 const unsigned char *convert;
 
 convert=NULL;

 if (data->PCFontKey!=FALSE)
  {
   if ( mode&MUIV_Editor_ImExMode_AmChar) convert=ConvertPC2Amiga;
  }
  else
  {
   if ( mode&MUIV_Editor_ImExMode_PCChar) convert=ConvertAmiga2PC;
  }

 buffermem=AllocVec(4096,1);
 inbuffer=0;

 if (buffermem==NULL) return (MUIV_Editor_Return_Disk_NoMemory);

 if (CacheClear(data)==FALSE)
  {
   DisplayBeep(NULL);
  }

 edbuf=data->Buffers[page];
 
 if (marked==FALSE)
  {
   cx=0;
   cy=0;
   GetLineInfoPg(data,page,&linf,edbuf->BufferLineCache-1);
   ex=linf.CharLen;
   ey=edbuf->BufferLineCache-1;
  }
  else
  {
   if (edbuf->MarkStartLine==-1) 
    {
     FreeVec(buffermem);
     return (MUIV_Editor_Return_Disk_NoMarkedText);
    }
   cx=edbuf->MarkStartColumn;
   cy=edbuf->MarkStartLine; 
   ex=edbuf->MarkStopColumn;
   ey=edbuf->MarkStopLine;
  }

 ansi.ForegroundColor=1;
 ansi.BackgroundColor=0;
 ansi.TextStyle=0;
 ansi.ANSICmdState=0;

 while (  (cy<ey ) || ( (cy==ey) && (cx<=ex) ) ) 

  {
   GetLineInfoPg(data,page,&linf,cy);
   if ( mode & MUIV_Editor_ImExMode_NoANSI)
    {
     unsigned char *charptr;
     unsigned char *bufptr;
     signed long dochar;
     ansi.TextBuffer=buffermem+inbuffer;
     ansi.CharLength=linf.CharLen;
     if ( (cy==ey) && ((ex+1)<=linf.CharLen)) ansi.CharLength=ex+1;
     ansi.TextLength=0;
     ansi.TextBufferSize=4000-inbuffer;
     ansi.CurrentColumn=cx;
     dochar=ansi.CharLength-cx;
     ansiret=MUIV_Editor_Return_OK;
     charptr=linf.Chars+cx;
     bufptr=ansi.TextBuffer;
     while ( dochar>0 )
      {
       if ( ansi.TextLength==ansi.TextBufferSize ) 
        {
         ansiret=MUIV_Editor_Return_ANSI_NotFinished;
         break;
        }
       *(bufptr++)=*(charptr++);
       ansi.CurrentColumn++;
       ansi.TextLength++;  
       dochar--;
      }
    }
    else
    {
     ansi.TextBuffer=buffermem+inbuffer;
     ansi.TextLength=0;
     ansi.TextBufferSize=4000-inbuffer;
     ansi.CharBuffer=linf.Chars;
     ansi.CharLength=linf.CharLen;
     if ( (cy==ey) && ((ex+1)<=linf.CharLen)) ansi.CharLength=ex+1;
     ansi.Styles=linf.Styles;
     ansi.UsedStyles=linf.StyleLen;
     ansi.CurrentColumn=cx;
     ansi.StreamCR=FALSE;
     ansiret=Stream_StreamToANSI(&ansi);
    } 

   if (convert!=NULL)
    {
     unsigned long i;
     unsigned char *cs;
     cs=ansi.TextBuffer;
     for (i=0;i<ansi.TextLength;++i)
      {
       *cs=convert[*cs];
       cs++;
      }
    }

   inbuffer+=ansi.TextLength;
   cx=ansi.CurrentColumn;
   if (ansiret==MUIV_Editor_Return_OK)
    {
     if (cx==linf.CharLen)
      {
       unsigned char *bufptr;
       bufptr=buffermem+inbuffer;
       if (mode & MUIV_Editor_ImExMode_CRLF)
        {
         *(bufptr++)='\015';
         *(bufptr++)='\012';
         inbuffer+=2;
        }
        else
        {
         if (mode & MUIV_Editor_ImExMode_CR)
          {
           *(bufptr++)='\015';
           inbuffer++;
          }
          else
          {
           *(bufptr++)='\012';
           inbuffer++;
          }
        }
      }
     cx=0;
     cy++;
    }

   if (inbuffer>3800)
    {
     getbf=hookfunc(streamhandle,buffermem,inbuffer);
     if (getbf!=inbuffer) 
      {
       FreeVec(buffermem);
       return(MUIV_Editor_Return_Disk_DiskError);
      }
     inbuffer=0;

    }
  }
 if (inbuffer!=0)
  {
   getbf=hookfunc(streamhandle,buffermem,inbuffer);
   if (getbf!=inbuffer) 
    {
     FreeVec(buffermem);
     return(MUIV_Editor_Return_Disk_DiskError);
    }
   inbuffer=0;
  }

 FreeVec(buffermem);
 return(MUIV_Editor_Return_OK);
} 

signed long Load_Stream_GetLine(struct Class_Data *data,
            shookfunc hookfunc,void *streamhandle,unsigned long mode,
            struct EditorBuffer *edbuf,unsigned char *buffermem,
            unsigned long *inbuffer,const unsigned char *convert,
            unsigned char **ffptr)
{
 unsigned char *sptr;
 unsigned char *fptr;
 unsigned long slen;
 int validcrlf;
 
 sptr=buffermem+4096;
 slen=0;
 
 edbuf->ANSIInput.TextBuffer=buffermem+4096;
 edbuf->ANSIInput.TextBufferSize=4096;
 edbuf->ANSIInput.CharBuffer=data->CachedChar;
 edbuf->ANSIInput.CharBufferSize=4096;
 edbuf->ANSIInput.Styles=data->CachedStyle;
 edbuf->ANSIInput.StyleSize=128;
 edbuf->ANSIInput.CurrentColumn=0;
 edbuf->ANSIInput.StreamCR=FALSE;
 edbuf->ANSIInput.ANSICmdState=0;
 validcrlf=FALSE;
 fptr=*ffptr;
 while (1)
  {
   if (*inbuffer==0)
    {
     *inbuffer=hookfunc(streamhandle,buffermem,4096);
     if (*inbuffer==-1)
      {
       *inbuffer=0;
       return(2);
      }

     if (*inbuffer==0)
      {
       if (slen==0) return(1);
       break;
      }
     fptr=buffermem;
    }

   

   if ( (*fptr==0x0a) || (*fptr==0x0d) )
    {
     if (mode&MUIV_Editor_ImExMode_CR)
      {
       if (*fptr==0x0d)
        {
         ++fptr;
         --(*inbuffer);
         edbuf->ANSIInput.StreamCR=TRUE;
         break;
        }
      } 
     if (mode&MUIV_Editor_ImExMode_LF)
      {
       if (*fptr==0x0a)
        {
         ++fptr;
         --(*inbuffer);
         edbuf->ANSIInput.StreamCR=TRUE;
         break;
        }
      }
     if (mode&MUIV_Editor_ImExMode_CRLF)
      {
       if (*fptr==0x0d)
        {
         ++fptr;
         --(*inbuffer);
         validcrlf=TRUE;
         continue;
        }
       if ( (*fptr==0x0a) && (validcrlf) )
        {
         ++fptr;
         --(*inbuffer);
         edbuf->ANSIInput.StreamCR=TRUE;
         break;
        }
      }
    }
   validcrlf=FALSE;
   if (slen==4096)
    {
     edbuf->ANSIInput.StreamCR=TRUE;
     break;
    }
   slen++;
   *(sptr++)=*(fptr++);
   --(*inbuffer);
  }

 *ffptr=fptr;
 edbuf->ANSIInput.TextLength=slen;
 {
  int scr;
  scr=edbuf->ANSIInput.StreamCR;
  Stream_ANSIToStream(&edbuf->ANSIInput);
  edbuf->ANSIInput.StreamCR=scr;
 }
 data->CachedTextLen=edbuf->ANSIInput.CharLength;
 data->CachedStyleInfo=edbuf->ANSIInput.UsedStyles;
 if (convert!=NULL)
  {
   unsigned char *sptr;
   unsigned long slen;
   sptr=edbuf->ANSIInput.CharBuffer;
   slen=edbuf->ANSIInput.CharLength;
   while (slen>0)
    {
     *sptr=convert[*sptr];
     sptr++;
     slen--;
    }
  }
 return(0);
}

signed long Load_Stream(struct Class_Data *data,
     shookfunc hookfunc,
     void *streamhandle,unsigned long page,unsigned long mode,
     unsigned long insert)
{
 unsigned char *buffermem,*fptr;
 struct EditorBuffer *edbuf;

 unsigned long inbuffer;
 const unsigned char *convert;
 
 unsigned long thispage,savepage,savevalid,CursorFollow;

 convert=NULL;

 CursorFollow=FALSE;

 buffermem=AllocVec(4096*2,1);
 inbuffer=0;

 if (buffermem==NULL) return (MUIV_Editor_Return_Disk_NoMemory);

 if (CacheClear(data)==FALSE)
  {
   DisplayBeep(NULL);
  }

 inbuffer=hookfunc(streamhandle,buffermem,4096);
 fptr=buffermem;

 if (inbuffer==-1)
  {
   FreeVec(buffermem);
   return(MUIV_Editor_Return_Disk_DiskError);
  }

 /* Auto detecting code of linefeed */

 if ( (!(mode&MUIV_Editor_ImExMode_CR)) && (!(mode&MUIV_Editor_ImExMode_LF)) 
    && (!(mode&MUIV_Editor_ImExMode_CRLF)) )
  {
   char *sptr;
   unsigned long slen;
   signed int identify,identify2;
   identify=-1;identify2=-1;
   sptr=buffermem;
   slen=inbuffer;   
   while ( (identify2==-1) && (slen>0) )
    {
     char schar1;
     slen--;
     schar1=*(sptr++);
     if ( schar1==0x0d )
      {
       if ( (slen>=1) && (*sptr==0x0a) )
        {
         slen--;
         sptr++;
         if ( (identify!=-1) && (identify!=3) ) 
          {
           identify=-1;
          }
          else
          {
           identify2=identify;
           identify=3;
          }
        }
        else
        {
         if ( (identify!=-1) && (identify!=2) )
          {
           identify=-1;
          }
          else
          {
           identify2=identify;
           identify=2;
          }
        }
      }
     if (schar1==0x0a)
      {
       if ( (identify!=-1) && (identify!=1) )
        {
         identify=-1;
        }
        else
        {
         identify2=identify;
         identify=1;
        }
      }     
    }

   if (identify==-1)
    {
     mode|=MUIV_Editor_ImExMode_LF;
    }
    else
    {
     switch (identify)
      {
       case 1:
         mode|=MUIV_Editor_ImExMode_LF;
         break;
       case 2:
         mode|=MUIV_Editor_ImExMode_CR;
         break;
       case 3:
         mode|=MUIV_Editor_ImExMode_CRLF;
         break;
      }
    }
  }

 /* Auto detecting code for PC font files */

 if ( (!(mode&MUIV_Editor_ImExMode_AmChar)) &&
      (!(mode&MUIV_Editor_ImExMode_PCChar)) )
  {
   unsigned int i;
   unsigned short history[256];
   unsigned char *sptr;

   unsigned short highcharsum;

   for (i=0;i<256;++i) history[i]=0;
   sptr=buffermem;
   for (i=0;i<inbuffer;++i) history[*(sptr++)]++;

   highcharsum=0;
   for (i=128;i<256;++i) highcharsum+=history[i];

   if ((highcharsum*3)>inbuffer)
    {
     mode|=MUIV_Editor_ImExMode_PCChar; /*seems to be binary data due to*/                                        /*1/3 bytes with bit 7 set*/
    }
    else
    {
     mode|=MUIV_Editor_ImExMode_AmChar;
    }
  }

 if (data->PCFontKey!=FALSE)
  {
   if ( mode&MUIV_Editor_ImExMode_AmChar) convert=ConvertAmiga2PC;
  }
  else
  {
   if ( mode&MUIV_Editor_ImExMode_PCChar) convert=ConvertPC2Amiga;
  }
 edbuf=data->Buffers[page];

 thispage=FALSE;
 savepage=data->DisplayPage;
 savevalid=data->ValidDisplay;
 data->DisplayPage=page;
 if (savepage==page) thispage=TRUE;
 if (thispage==FALSE) data->ValidDisplay=FALSE;
 if ( (savevalid==FALSE) || ( (edbuf->HeadLine+data->GfxLines)
       >edbuf->CursorLine) ) 
  {
   CursorFollow=TRUE;
  }

 if (thispage==TRUE) data->Refresh=2;
 

 if (!insert)
  {
   CursorFollow=FALSE;
   ClearBuffer(edbuf);
   edbuf->ImportMode=mode;
   fptr=buffermem;
   while (1)
    {
     unsigned long errcode;
     if (CacheSet(data,edbuf->CursorLine)==FALSE)
      {

       CacheClear(data);
       data->DisplayPage=savepage;
       data->ValidDisplay=savevalid;
       FreeVec(buffermem);
       if (page==data->DisplayPage)
        {
         CompleteRefresh(data);
         MUI_Redraw ((Object*) data->RootObject,MADF_DRAWUPDATE);
        }
       return(MUIV_Editor_Return_Disk_BuffersTooSmall);
      }

     if ((errcode=Load_Stream_GetLine(data,hookfunc,streamhandle,mode,
          edbuf,buffermem,&inbuffer,convert,&fptr))==2)
      {
       CacheClear(data);
       data->DisplayPage=savepage;
       data->ValidDisplay=savevalid;
       FreeVec(buffermem);
       if (page==data->DisplayPage)
        {
         CompleteRefresh(data);
         MUI_Redraw ((Object*) data->RootObject,MADF_DRAWUPDATE);
        }
       return(MUIV_Editor_Return_Disk_DiskError);
      }

     if (errcode==1)
      {
       CacheClear(data);
       break;
      }
     if (edbuf->ANSIInput.StreamCR==TRUE) ++edbuf->CursorLine;
     if (CacheClear(data)==FALSE)
      {
       edbuf->CursorLine--;
       DisplayBeep(NULL);
      }
    }

  }


 if (CursorFollow==TRUE)
    {
     if (savevalid==FALSE)
      {
       edbuf->HeadLine=edbuf->CursorLine;
       edbuf->HeadColumn=0;
      }
      else
      {
       if ((edbuf->HeadLine+data->GfxLines)<=edbuf->CursorLine)
        {
         edbuf->HeadLine=edbuf->CursorLine-data->GfxLines+1;
         if (thispage!=FALSE) CompleteRefresh(data);
        }
      }
    }
 

 data->DisplayPage=savepage;   
 data->ValidDisplay=savevalid;
 FreeVec(buffermem);
 if (page==data->DisplayPage)
  {
   CompleteRefresh(data);
   MUI_Redraw ((Object *)data->RootObject,MADF_DRAWUPDATE);
  }

 return(MUIV_Editor_Return_OK);



}

