//edit.ctp Copyright (C) 1989-2000 I.Pedley (CTPP) Sun 30-Apr-2000 at 14:30:21

//editor sub-functions, including modified line buffer management

#pragma breakpoints on

#include {stdlib.htm}
#include {string.htm}
#include {drive.htm}
#include {accdis.htm}
#include {bios.htm}
#include {chaoskey.htm}

#include {os3.htm}
#include {e3.htm}


EX  E3  ectl;
EX  E3  E[MAXEFILES];
EX  UL  efiles;
EX  UL  ecur;

UL  linelength  (CH* str,UL maxlen);
UL  lflinelength(CH* str,UL maxlen);

    E3* ce;

EX  UL  insert;
#define UDGRAN  100
    CH*  udbuf;
    UL   udidx;
    UL   udlines;



SL  deleteline     (E3* e)
{
    if(e->cury>=e->lines){return 0;}
    SL  tomove=e->lines-e->cury; //include one blank line from extras
    CH* text=e->buf+e->cury*MEMLINELEN;
    CH* ud;
    CH* ud1;

    if(tomove>0)
        {
         if(udidxlines--;
    e->modified=1;
    return 0;
}
SL  insertblankline(E3* e)
{
    CH* ebuf;

    if(e->lines==e->maxlines)
        {
         ebuf=malloc((e->lines+EDITEXTRAS)*MEMLINELEN);
         if(!ebuf)
            {
             displayat(49,40,"|c4Out of memory for edit buffers");
             return 1;
            }
         memcpy(ebuf,e->buf,e->lines*MEMLINELEN);
         free(e->buf);
         e->buf=ebuf;
         e->maxlines+=EDITEXTRAS;
         displayat(49,40,"|c4Edit buffer increased to %4l lines",&e->maxlines);
        }

    SL  tomove=e->lines-e->cury;
    CH* text=e->buf+e->cury*MEMLINELEN;

    while(tomove<0){e->lines++;tomove++;} //allow for cursor beyond end of file
    if(tomove>0){memmove(text+MEMLINELEN,text,tomove*MEMLINELEN);}
    memset (text,0x20,MEMLINELEN);

    e->lines++;
    e->modified=1;
    return 0;
}
SL  repeatline     (E3* e)
{
    if(insertblankline(e)){return 1;}
    CH* text=e->buf+e->cury*MEMLINELEN;

    memcpy(text,text+MEMLINELEN,MEMLINELEN);
    e->modified=1;
    return 0;
}
SL  retypeline     (E3* e)
{
    CH* text;
    CH* ud;

    if(udidx)
       {
        if(insertblankline(e)){return 1;}
        text=e->buf+e->cury*MEMLINELEN; //e->buf can change in insertblankline!
        udidx--;
        ud  =udbuf+udidx*MEMLINELEN;
        memcpy (text,ud,MEMLINELEN);
       }
    e->modified=1;
    return 0;
}
SL  insertblock(E3* e)
{
//copy undelete buffer to current file, then restore undelete buffer contents
    UL n=udidx;
    while(udidx)
        {
         if(retypeline(e)){return 1;}
        }
    udidx=n;
    return 0;
}
SL  clearundeletebuffer(VD)
{
    udidx=0;
}
SL  makeundeletebuffer     (VD)
{
    udlines=UDGRAN;
    udbuf=malloc(udlines*MEMLINELEN);
    if(!udbuf)
        {
         clidisplay("Insufficient memory");return 1;
        }
    udidx=0;
    return 0;
}

    CH* argbuf;

SL  destroyundeletebuffer  (VD)
{
    if(argbuf){free(argbuf);}
    free(udbuf);return 0;
}

    UL arglines;
    UL argwidth;

VD  saveargbuffer  (E3* e)
{
    CH* text=e->buf+e->argy*MEMLINELEN+e->argx;
    UL  n;
    UL  w=argwidth=e->argw-e->argx+1;
    UL  h=arglines=e->argh-e->argy+1;

    if(argbuf){free(argbuf);}
    argbuf=(CH*)calloc(h,MEMLINELEN);
    if(!argbuf){brk arglines=0;return;}
    memset(argbuf,0x20,h*MEMLINELEN);

    for(n=0;ncurx=e->argx;
    e->cury=e->argy;
}
VD  insertargbuffer(E3* e)
{
    CH* text=e->buf+e->cury*MEMLINELEN+e->curx;
    UL  tomove=MEMLINELEN-e->curx-argwidth;
    UL  n;
    CH* ptr;

    if(argwidth>=MAXLINELEN)
        {
         ptr=argbuf+(arglines-1)*MEMLINELEN;    //insert last line first
         for(n=0;nbuf+e->cury*MEMLINELEN+e->curx;
             memcpy(text,ptr,argwidth);         //text buffer may change after
             ptr-=MEMLINELEN;                   //after insertblankline() so
            }                                   //refresh CH* text each time
        }
    else
        {
         for(n=0;nmodified=1;
}
VD  deleteargbuffer(E3* e)
{
    saveargbuffer(e);

    CH* text=e->buf+e->argy*MEMLINELEN;
    CH* text1=text+e->argx;
    SL  n,m,o;
    UL  w=argwidth=e->argw-e->argx+1;
    UL  h=arglines=e->argh-e->argy+1;

    if(argwidth>=MAXLINELEN)
        {
         m=e->lines-e->cury-h;
         if(m>0)
            {
             memcpy(text,text+h*MEMLINELEN,m*MEMLINELEN);
            }
         e->lines-=h;
        }
    else
        {
         for(n=0;nargx;
              if(o>0){memcpy(text1,text1+w,o);}
              text+=MEMLINELEN;
              text1+=MEMLINELEN;
             }
        }
//move cursor to top-left of arg block, and clear arg box
    e->curx=e->argx;
    e->cury=e->argy;
    e->argtoggle=0;
    e->modified=1;
}
//SL  lpt_sendchar(UL lpt,UL c);
//SL  lpt_sendstring(CH* str);
//VD  hpsmallprint(VD);
//VD  printargbuffer (E3* e)
//{
//    SL  n,m,o;
//    CH* text=e->buf+e->argy*MEMLINELEN+e->argx;
//    UL  h=arglines=e->argh-e->argy+1;
//    if(h<=1){return;}
//    CH* ptr;
//    lpt_sendstring("\x1b\x45");       //reset printer
//    hpsmallprint();
//
//    lpt_sendstring("\x1b&a6L");    //set left margin to 6
//
//    for(n=0;n=0x20){lpt_sendchar(0,*ptr);}
//             else          {lpt_sendchar(0,0x20);}
//             ptr++;
//            }
//         lpt_sendchar(0,0x0d);
//         lpt_sendchar(0,0x0a);
//         text+=MEMLINELEN;
//        }
//    lpt_sendchar(0,0x0c);
////move cursor to top-left of arg block, and clear arg box
//    e->curx=e->argx;
//    e->cury=e->argy;
//    e->argtoggle=0;
//    e->modified=1;
//}

UL  linestart(CH* str,UL maxlen)
{
    SL n;
    for(n=0;nbuf+e->cury*MEMLINELEN;
    switch(key)
       {
        case TAB:
            e->curx+=4;
            e->curx&=-4;
            if(e->curx>=MAXLINELEN)
                {
                 e->curx-=4;
                }
            break;
        case (SHIFT|TAB):
            if(e->curx)
                {
                 if(!(e->curx&3)){e->curx-=4;}
                 else            {e->curx&=-4;}
                }
            break;
        case ENTER:
        case NUMENTER:
            //brk
            if(insert)
                {
//#pragma breakpoint
                 insertblankline(e);
                 text=e->buf+e->cury*MEMLINELEN;  //as e->buf may have changed!
                 n=linelength(text+MEMLINELEN,MAXLINELEN);
                 if(e->curx)
                    {
                    // if(n>=e->curx)
                     if(n>e->curx)
                        {
//                         rem=n-e->curx;
//                         memcpy(text,text+MEMLINELEN,e->curx);
//                         text+=MEMLINELEN;
//                         memcpy(text,text+e->curx,MAXLINELEN-e->curx);
//                         memset(text+n-e->curx,0x20,MAXLINELEN-e->curx);
                         rem=n-e->curx;
                         memcpy(text,text+MEMLINELEN,e->curx);
                         text+=MEMLINELEN;
                         memcpy(text,text+e->curx,rem);
                         memset(text+n-e->curx,0x20,MAXLINELEN-rem);
                        }
                     else
                        {
                         memcpy(text,text+MEMLINELEN,e->curx);
                         text+=MEMLINELEN;
                         memset(text,0x20,MAXLINELEN);
                        }
                    }
                 e->modified=1;
                 e->curx=0;
                }
            else
                {
                 n=linestart(text+MEMLINELEN,MAXLINELEN);
                 e->curx=n;
                }
            e->cury++;
            break;
        case BACKSPACE:
            if(insert)
                {
                 if(e->curx)
                    {
                     n=linelength(text,MAXLINELEN);
                     if(e->curx>n)
                        {
                         //do nothing, cursor is beyond end of text on this line
                        }
                     else
                        {
//                         brk
                         tomove=n+1-e->curx;
                         memmove(text+e->curx-1,text+e->curx,tomove);
                        }
                     e->curx--;
                    }
                 else if(e->cury)
                    {
//                     brk
                     tomove=linelength(text,MAXLINELEN);
                     text-=MEMLINELEN;
                     n=linelength(text,MAXLINELEN);
                     if(!tomove) //backspace at beginning of a blank line
                        {        //just deletes the line
                         deleteline(e);
                        }
                     else if(tomove+nlines-e->cury; //include one blank line from extras
                        // text=e->buf+e->cury*MEMLINELEN;
                        // memmove(text,text+MEMLINELEN,tomove*MEMLINELEN);
                        }
                     e->cury--;
                     e->curx=n;
                    }
                }
            else
                {
                 if(e->curx){e->curx--;}
                 else if(e->cury)
                    {
                     text-=MEMLINELEN;
                     n=linelength(text,MAXLINELEN);
                     e->cury--;
                     e->curx=n;
                    }
                }
            break;
        case NDEL:
            if(e->argtoggle)
                {
                 saveargbuffer(e);
                 ptr=e->buf+e->cury*MEMLINELEN+e->curx;//<--recalc text position
                 if(argwidth==MAXLINELEN+1)            //as cursor is moved
                    {                                  //by saveargbuffer
                     //we are deleting whole lines
                     tomove=arglines;
                     if(e->cury>=e->lines){break;}
                     if(tomove>e->lines-e->cury){tomove=e->lines-e->cury;}
                     memmove(ptr,ptr+arglines*MEMLINELEN,tomove*MEMLINELEN);
                     if(e->lines>arglines){e->lines-=arglines;}
                     else                 {e->lines=0;}
                     memset (e->buf+e->lines*MEMLINELEN,0x20,tomove*MEMLINELEN);
                    }
                 else
                    {
                     tomove=MAXLINELEN-e->curx-argwidth+1;
                     ptr=e->buf+e->cury*MEMLINELEN+e->curx;//<--recalc text position
                     for(n=0;nargtoggle=0;
                }
            else if(e->curxcurx; //include terminating null
                ptr=text+e->curx;
                if(tomove)
                   {
                    memcpy(ptr,ptr+1,tomove);
                   }
               }
            e->modified=1;
            break;
        default:   //i.e. isprint()-able character
            if(insert)
                {
                 tomove=MAXLINELEN-e->curx;
                 ptr=text+e->curx;
                 memmove(ptr+1,ptr,tomove);
                 *ptr=key;
                 e->curx++;
                }
            else
                {
                 ptr=text+e->curx;
                 *ptr=key;
                 e->curx++;
                }
            if(e->cury>=e->lines)
                {
                 e->lines=e->cury+1;
                }
            e->modified=1;
            break;
       }
}
UL  dumptrailingemptylines(E3* e)
{
    SL n,m;
//    CH* text=e->buf+(e->maxlines-1)*MEMLINELEN;
    CH* text=e->buf+(e->lines-1)*MEMLINELEN;
//    for(n=e->maxlines-1;n>=0;n--)
    for(n=e->lines-1;n>=0;n--)
        {
         m=linelength(text,MAXLINELEN);
         if(m)
            {
             e->lines=n+1;return 0;
            }
         text-=MEMLINELEN;
        }
    e->lines=0;
    return 0;
}
UL  makeasciibuf(E3* e)
{
//add CR and LF control characters to editor file lines, condensing the
//buffer as we go ready to write out to disk
//note that the condensed text is still in e->buf, for this to work correctly
//MEMLINELEN must be >= MAXLINELEN+2
//lines which are of length MAXLINELEN are saved without trailing CR LF

    dumptrailingemptylines(e);

    CH* ptr1=e->buf;
    CH* ptr =e->buf;

    UL  n,m;
    UL  buflen=linelength(ptr,MAXLINELEN);
    ptr=ptr+buflen;
    *ptr++=0x0d;
    *ptr++=0x0a;
    ptr1=e->buf+MEMLINELEN;
    buflen+=2;

    for(n=1;nlines;n++)
        {
         m=linelength(ptr1,MAXLINELEN);
         memcpy(ptr,ptr1,m);
         ptr=ptr+m;
         if(m==MAXLINELEN)
            {
             buflen+=m;
            }
         else
            {
             *ptr++=0x0d;
             *ptr++=0x0a;
             buflen+=m+2;
            }
         ptr1+=MEMLINELEN;
        }

    return buflen;
}

//SL  cfdownload(CHAOSFILE* cf,PATH* sp,VD* buf,UL len);
//SL  splitpath(CH* str,PATH* sp);
SL  downloadfile(CH* fname,PATH* sp,UL fsiz,VD* buf,UL archive);

SL  saveE3(E3* e,UL preserve)
{
    CH* sbuf=NULL;
    if(preserve)
        {
         sbuf=malloc(e->lines*MEMLINELEN);
         if(sbuf)
            {
             memcpy(sbuf,e->buf,e->lines*MEMLINELEN);
            }
        }

    UL  buflen=makeasciibuf(e);
    UL  ret=downloadfile(e->name,&e->sp,buflen,e->buf,0);
//    UL  ret=downloadfile(e->name,&e->sp,buflen,e->buf,1);

    if(sbuf)
        {
         memcpy(e->buf,sbuf,e->lines*MEMLINELEN);
         free(sbuf);
        }

    e->modified=0;
    return ret;
}

SL  makecontrolfileline(E3* e,CH* msg)
{
    strcpy(msg,e->name);
    strcat(msg," ");itoa(e->wy,  msg+strlen(msg),10);
    strcat(msg," ");itoa(e->wx,  msg+strlen(msg),10);
    strcat(msg," ");itoa(e->cury,msg+strlen(msg),10);
    strcat(msg," ");itoa(e->curx,msg+strlen(msg),10);
    strcat(msg,"\r\n");
    return strlen(msg);
}

SL  savecontrolfile(E3* ec)
{
    UL  n,m;
    E3* e=E;
    UL  buflen=0;
    CH  msg[512];
    CH* ptr;

    UL  cl=ec->lines;
    if(cl>MAXEFILES){cl=MAXEFILES;}

    CH* text=ec->buf;

    for(n=0;nloaded)
            {
             buflen+=makecontrolfileline(e,msg);
            }
         else
            {
             buflen+=linelength(text,MAXLINELEN)+2;
            }
         text+=MEMLINELEN;
         e++;
        }

    if(!buflen){return 0;}              //nothing to do is no error

    CH* buf=(CH*)calloc(buflen+1,1);    //add 1 for terminal null byte!
    if(!buf){return 1;}
    ptr=buf;


    text=ec->buf;
    e=E+ecur;
    if(e->loaded)
        {
         ptr+=makecontrolfileline(e,ptr);
        }

    e=E;
    for(n=0;nloaded)
                {
                 ptr+=makecontrolfileline(e,ptr);
                }
             else
                {
                 m=linelength(text,MAXLINELEN);
                 memcpy(ptr,text,m);
                 strcat(ptr,"\r\n");
                 ptr+=m+2;
                }
            }
         text+=MEMLINELEN;
         e++;
        }

    UL  ret=downloadfile(ec->name,&ec->sp,buflen,buf,0);
    free(buf);
    return ret;

}

EX  CH* ctfname;
SL  patch(E3* e,UL size);

SL  createcontrolfile(E3* e)
{
    if(patch(e,0)){return 1;}
    strcpy(e->name,ctfname);
    strcpy(e->sp.name,"e");
    strcpy(e->sp.ext, "control");

    return 0;
}

SL  alreadyedited(E3* e,CH* name)
{
//run through control file matching name to control file lines

    UL n;
    CH* text=e->buf;
    CH* ptr;
    CH  c;

    for(n=0;nlines;n++)
        {
//         if(!strncmp(text,name,strlen(name))){return n;}
         ptr=strchr(text,' ');
         if(ptr)
            {
             c=*ptr;
             *ptr=0;
             if(!strcmp(text,name)){*ptr=c;return n;}
             CH tmp[256];
             strcpy(tmp,name);strcat(tmp,".htm");
             if(!strcmp(text,tmp )){*ptr=c;return n;}
             *ptr=c;
            }
         text+=MEMLINELEN;
        }
    return -1;
}
SL  createnewE3   (E3* e,CH* name)
{
    memset(e,0,sizeof(E3));
    e->buf=malloc((e->lines+EDITEXTRAS)*MEMLINELEN);
    if(!e->buf)
        {
         displayat(49,40,"|c4Out of memory for edit buffers");
         return 1;
        }
    e->maxlines=EDITEXTRAS;
    memset (e->buf,0x20,e->maxlines*MEMLINELEN);
    strcpy(e->name,name);
    return 0;
}
SL  lfterminate(E3* e)
{
//add LF control character to the end of each editor file line,
//and insert line length as first character
//ready to pass buffer in to compiler(!)

    CH* text=e->buf;

    UL  n,m;

    for(n=0;nlines;n++)
        {
         m=linelength(text,MAXLINELEN);
         memmove(text+1,text,m);
         text[0]=m;
         if(mlines*MEMLINELEN;
    CH* buf=malloc(buflen);
    if(!buf){return NULL;}
    CH* ptr=buf+sizeof(E3);
    E3* e=(E3*)buf;
//    *e=*ein;
    memcpy(e,ein,sizeof(E3));
    e->buf=ptr;
    memcpy(e->buf,ein->buf,e->lines*MEMLINELEN);
    return e;
}