
/*
 * CMD1.C   (was TEXT1.C)
 *
 *      (C)Copyright 1987 by Matthew Dillon,    All Rights Reserved
 */

#include "defs.h"
#include "cb.h"
#include <ctype.h>
#include <reqtools/reqtools.h>

#include "replace.h"

typedef struct Process PROC;

int confirm_replace(void);
int ConfirmReplace = 0;

#define nomemory()  { memoryfail = 1; }

char RecallBuf[256];


/*
void setpen(int line)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;
    short bpen;

    short pen = (ep == BEp && line >= BSline && line <= BEline) ? ep->HGPen : ep->FGPen;
    if (Comlinemode)
        pen = ep->FGPen;
    if (pen != rp->FgPen)
        SetAPen(rp, pen);
    bpen = (pen == ep->FGPen) ? ep->BGPen : ep->HGBGPen;
    if (bpen != rp->BgPen)
        SetBPen(rp, bpen);
}
*/

int is_in_block(int line, int col)
{
   int ret = 0;

   if (Ep == BEp)
   {
      switch (Blocktype)
      {
         case BLOCK_CHARACTER:
            if ((line > BSline) || ((line == BSline) && (col >= BSchar)))
               if ((line < BEline) || ((line == BEline) && (col <= BEchar)))
                  ret = 1;
            break;
         case BLOCK_LINE:
            if (line >= BSline && line <= BEline)
               ret = 1;
         default:
            break;
      }
   }
   return ret;
}


void setpen(int line, int col)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;
    short bpen, pen;

    if (is_in_block(line, col))
       pen = ep->HGPen;
    else
       pen = ep->FGPen;

    if (Comlinemode)
        pen = ep->FGPen;
    if (pen != rp->FgPen)
        SetAPen(rp, pen);
    bpen = (pen == ep->FGPen) ? ep->BGPen : ep->HGBGPen;
    if (bpen != rp->BgPen)
        SetBPen(rp, bpen);
}


int text_init(ED *oldep, WIN *win, struct NewWindow *nw)
{
    char buf[10];
    ED *e;

    text_switch(NULL);
    e = (ED *)allocb(sizeof(ED));
    if (e == NULL)
        return(0);
    setmem(e, sizeof(ED), 0);
    e->Win = win;
    if (oldep) {
        e->dirlock = (long)DupLock((BPTR)oldep->dirlock);

        movmem(&oldep->BeginConfig, &e->BeginConfig, (char *)&e->EndConfig - (char *)&e->BeginConfig);

        if (oldep->Font) {
            e->Font = oldep->Font;
            ++e->Font->tf_Accessors;
            if (win)
                SetFont(win->RPort, e->Font);
        }
        e->IWiny = oldep->IWiny + 16;
    } else {
        PROC *proc = (PROC *)FindTask(NULL);
        e->dirlock = (long)DupLock((BPTR)proc->pr_CurrentDir);

        e->Insertmode = 1;
        e->Tabstop = 4;
        e->WWCol = DefaultParcol;
        e->Margin= DefaultMargin;
        e->FGPen = 1;
        e->BGPen = 0;
        e->HGPen = 2;
        e->HGBGPen = 3;
        loadconfig(e);
    }
    e->Lines = 1;
    e->Maxlines = 32;
    e->List = (ubyte **)allocl(e->Maxlines);
    e->List[0] = allocb(1);
    e->List[0][0] = Current[0] = Clen = 0;
    AddHead((LIST *)&DBase, (NODE *)e);
    strcpy(e->Name, "unnamed");
    Ep = e;

    if (nw) {
        if (e->Winwidth && e->Winheight) {
            nw->LeftEdge= e->Winx;
            nw->TopEdge = e->Winy;
            nw->Width   = e->Winwidth;
            nw->Height  = e->Winheight;
        } else {
            nw->LeftEdge= 0;
            nw->TopEdge = 0;
            nw->Width   = 640;
            nw->Height  = 200;
        }
        nw->DetailPen = e->BGPen;
        nw->BlockPen  = e->FGPen;
    }
    return(1);
}

int text_switch(WIN *win)
{
    ED *e;

    if (win)
        text_sync();
    if (win) {
        for (e = (ED *)DBase.mlh_Head; e->Node.mln_Succ; e = (ED *)e->Node.mln_Succ) {
            if (e->Win == win) {
                Ep = e;
                text_load();
                if (!Ep->iconmode) {
                    set_window_params();
                    window_title();
                }
                return(1);
            }
        }
        return(0);
    }
}


int text_sync(void)
{
    ED *ep = Ep;
    char redraw = 0;
    short len;
    ubyte *ptr;

    for (len = strlen(Current) - 1; len >= 0 && Current[len] == ' '; --len)
        Current[len] = '\0';
    Clen = len + 1;
    if (!Comlinemode) {
        if (strlen(ep->List[ep->Line]) != Clen) {
            if (ptr = allocb(Clen+1)) {
                ep->Modified = 1;
                Overide = 0;
                FreeMem(ep->List[ep->Line], strlen(ep->List[ep->Line])+1);
                ep->List[ep->Line] = ptr;
            } else {
                nomemory();
                strcpy(Current, ep->List[ep->Line]);
                Clen = strlen(Current);
            }
        } else {
            if (strcmp(ep->List[ep->Line], Current)) {
                ep->Modified = 1;
                Overide = 0;
            }
        }
        strcpy(ep->List[ep->Line], Current);
    }
    if (Nsu == 0) {
        if (ep->Column - ep->Topcolumn >= Columns || ep->Column < ep->Topcolumn) {
            redraw = 1;

            ep->Topcolumn = ep->Column - (Columns>>1);

            if (ep->Topcolumn < 0)
                ep->Topcolumn = 0;
        }
        if (ep->Line - ep->Topline >= Rows || ep->Line < ep->Topline) {
            redraw = 1;

            ep->Topline = ep->Line - (Rows>>1);

            if (ep->Topline < 0)
                ep->Topline = 0;
        }
    }
    while (ep->Column > Clen)
        Current[Clen++] = ' ';
    Current[Clen] = '\0';
    if (redraw)
        text_redisplay();
    return((int)redraw);
}

int text_load(void)
{
    if (Comlinemode)
        return(0);
    strcpy(Current, Ep->List[Ep->Line]);
    Clen = strlen(Current);
    while (Ep->Column > Clen)
        Current[Clen++] = ' ';
    Current[Clen] = '\0';
}

int text_colno(void)
{
    return(Ep->Column);
}

int text_lineno(void)
{
    return(Ep->Line+1);
}

int text_lines(void)
{
    return(Ep->Lines);
}

int text_cols(void)
{
    return((int)Clen);
}

int text_imode(void)
{
    return((int)Ep->Insertmode);
}

int text_tabsize(void)
{
    return((int)Ep->Tabstop);
}

unsigned char *text_name()
{
    return(Ep->Name);
}

void text_uninit(void)
{
    ED *ep = Ep;

    PMKill(ep);
    freelist((char **)ep->List, ep->Lines);
    FreeMem(ep->List, ep->Maxlines * sizeof(char *));

    if (BEp == ep) {
        BEp = NULL;
        BSline = BEline = BSchar = BEchar = -1;
    }
    Remove((NODE *)ep);
    if (ep->Font) {
        SetFont(ep->Win->RPort, ep->Win->WScreen->RastPort.Font);
        CloseFont(ep->Font);
    }
    UnLock((BPTR)ep->dirlock);
    FreeMem(ep, sizeof(ED));
    if (((ED *)DBase.mlh_Head)->Node.mln_Succ) {
        Ep = (ED *)DBase.mlh_Head;
        text_load();
    } else {
        Ep = NULL;
    }
}

void inversemode(int n)
{
    RP *rp = Ep->Win->RPort;

    if (n) {
        SetAPen(rp, ~Ep->BGPen);
        SetDrMd(rp, JAM2|INVERSVID);
    } else {
        setpen(Ep->Line, Ep->Column);
        SetDrMd(rp, JAM2);
    }
}

void text_cursor(int n)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;

    movetocursor();
    inversemode(n);
    if (Current[ep->Column])
        Text(rp, Current+ep->Column, 1);
    else
        Text(rp, " ", 1);
    inversemode(0);
}

void text_position(int col, int row)
{
    ED *ep = Ep;
    text_sync();
    if (col == 0)
        col = -1;
    ep->Column = ep->Topcolumn + col;
    if (ep->Column > 254)
        ep->Column = 254;
    if (ep->Column < 0)
        ep->Column = 0;
    ep->Line = ep->Topline + row;
    if (ep->Line >= ep->Lines)
        ep->Line = ep->Lines - 1;
    if (ep->Line < 0)
        ep->Line = 0;
    text_load();
    text_sync();
}

void displayblock(int on)
{
    long start = Ep->Topline;
    long lines = BEline - BSline + 1;

    if (start < BSline)
        start = BSline;
    if (!on) {
        BSline = BEline = BSchar = BEchar = -1;
        BEp = NULL;
        Marking = 0;
    }
    /* if (Ep == BEp) removed by KL */
        text_displayseg(start - Ep->Topline, lines);
}

void text_redrawblock(int ok)
{
    WIN *savewin = NULL;

    if (BEp) {
        if (BEp != Ep) {
            savewin = Ep->Win;
            text_switch(BEp->Win);
        }
        if (BSline <= BEline && BSline >= 0 && BEline < Ep->Lines) {
            if (!ok) {
                BEp = NULL;
                BSline = BEline = BSchar = BEchar = -1;
            }
            text_displayseg(0, Rows);
        }
        if (savewin)
            text_switch(savewin);
    }
    if (!ok) {
        BEp = NULL;
        BSline = BEline = BSchar = BEchar = -1;
        Marking = 0;
    }
}

int highlight(int line)
{
   int col = Ep->Topcolumn;
   int start, stop;
   int linelength = strlen(Ep->List[line]);
/*
   if ((Ep == BEp) && (! Blockempty) && (!( BSchar == BEchar) && (BSline == BEline)))
*/
   switch (Blocktype)
   {
      case BLOCK_CHARACTER:
         if ((Ep == BEp) && (! Blockempty))
         {
            if (line < BSline || line > BEline)
               return  0;  /* No highlighting */
            else if(line > BSline && line < BEline)
               return  2;  /* Highlight entire line */
            else if ((BSline != BEline) && (line == BSline))
            {
               start = BSchar; stop = 256;
            }
            else if ((BSline != BEline) && (line == BEline))
            {
               start = 0; stop = BEchar;
            }
            else
            {
               start = BSchar; stop = BEchar;
            }
            {
               if ((start <= col) && ((stop >= linelength) || (stop - col > Columns)))
                  return 2;
               else if ((start <= col) && (stop < linelength))
                  return 1;
               else if ((start > col) && ((stop >= linelength) || (stop - col > Columns)))
                  return 3;
               else if ((start > col) && (stop < linelength))
                  return 4;
            }
            printf("Highlight: unknown situation\n");
            return 0;
         }
         else
            return 0;
         break;
      case BLOCK_LINE:
         if (Ep == BEp && line >= BSline && line <= BEline)
            return 2;
         else
            return 0;
         break;
      default:
         break;
   }
}

/* Changed by Karl Lukas 06/94: Less flicker */

void text_displayseg(int start, int n)
{
    short i, c;
    ubyte *ptr;
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;
    RP rp2 = *rp;
    int len;

    int hgpen = ep->HGPen;
    int fgpen = ep->FGPen;
    int bgpen = ep->BGPen;
    int hgbgpen = ep->HGBGPen;

    if (Nsu)
        return;
    for (i = start; i < start + n && i < Rows && ep->Topline + i < ep->Lines; ++i) {
        if (Comlinemode)
        {
            if (ep->Topline + i != ep->Line)
                continue;
            ptr = Current;
        }
        else
            ptr = ep->List[ep->Topline + i];

        for (c = ep->Topcolumn; c && *ptr; ++ptr, --c);

        if (! Comlinemode)
        {
           switch (highlight(ep->Topline + i))
           {
              case 0:  /* No highlighting */
                 if (rp->BgPen != bgpen)
                    SetBPen(rp, bgpen);
                 if (rp->FgPen != fgpen)
                    SetAPen(rp, fgpen);
                 if (rp2.FgPen != bgpen)
                    SetAPen(&rp2, bgpen);
                 c = strlen(ptr);
                 RectFill(&rp2, COL(c), ROW(i), Xbase + Xpixs - 1, ROW(i+1)-1);
                 if (c)
                 {
                    Move(rp, COLT(0), ROWT(i));
                    Text(rp, ptr, (c > Columns) ? Columns : c);
                 }
                 break;
              case 3:  /* highlight end of line */
                 if (rp->BgPen != hgbgpen)
                    SetBPen(rp, hgbgpen);
                 if (rp->FgPen != hgpen)
                    SetAPen(rp, hgpen);
                 if (rp2.FgPen != hgbgpen)
                    SetAPen(&rp2, hgbgpen);
                 RectFill(&rp2, COL(0), ROW(i), Xbase + Xpixs - 1, ROW(i+1)-1);
                 len = BSchar - ep->Topcolumn;
                 c = strlen(ptr);
                 if (c)
                 {
                    Move(rp, COLT(0), ROWT(i));
                    Text(rp, ptr, (c > Columns) ? Columns : c);
                 }
                 if (len > 0 && c)
                 {
                    SetAPen(rp, fgpen);
                    SetBPen(rp, bgpen);
                    Move(rp, COLT(0), ROWT(i));
                    Text(rp, ptr, (len > Columns) ? Columns : len);
                 }
                 break;
              case 1:  /* highlight front of line */
                 if (rp->BgPen != bgpen)
                    SetBPen(rp, bgpen);
                 if (rp->FgPen != fgpen)
                    SetAPen(rp, fgpen);
                 if (rp2.FgPen != bgpen)
                    SetAPen(&rp2, bgpen);
                 RectFill(&rp2, COL(0), ROW(i), Xbase + Xpixs - 1, ROW(i+1)-1);
                 len = BEchar - ep->Topcolumn + 1;
                 c = strlen(ptr);
                 if (c)
                 {
                    Move(rp, COLT(0), ROWT(i));
                    Text(rp, ptr, (c > Columns) ? Columns : c);
                 }
                 if (len > 0 && c)
                 {
                    SetAPen(rp, hgpen);
                    SetBPen(rp, hgbgpen);
                    Move(rp, COLT(0), ROWT(i));
                    Text(rp, ptr, (len > Columns) ? Columns : len);
                 }
                 break;
              case 4:
                 if (rp->BgPen != bgpen)
                    SetBPen(rp, bgpen);
                 if (rp->FgPen != fgpen)
                    SetAPen(rp, fgpen);
                 if (rp2.FgPen != bgpen)
                    SetAPen(&rp2, bgpen);
                 RectFill(&rp2, COL(0), ROW(i), Xbase + Xpixs - 1, ROW(i+1)-1);
                 c = strlen(ptr);
                 if (c)
                 {
                    Move(rp, COLT(0), ROWT(i));
                    Text(rp, ptr, (c > Columns) ? Columns : c);
                 }
                 c = BEchar - BSchar + 1;
                 if (c > 0)
                 {
                    SetAPen(rp, hgpen);
                    SetBPen(rp, hgbgpen);
                    Move(rp, COLT(BSchar - ep->Topcolumn), ROWT(i));
                    Text(rp, ptr + BSchar - ep->Topcolumn, c);
                 }
                 break;
              case 2:  /* highlight whole line */
                 if (rp->BgPen != hgbgpen)
                    SetBPen(rp, hgbgpen);
                 if (rp->FgPen != hgpen)
                    SetAPen(rp, hgpen);
                 if (rp2.FgPen != hgbgpen)
                    SetAPen(&rp2, hgbgpen);
                 RectFill(&rp2, COL(0), ROW(i), Xbase + Xpixs - 1, ROW(i+1)-1);
                 c = strlen(ptr);
                 if (c)
                 {
                    Move(rp, COLT(0), ROWT(i));
                    Text(rp, ptr, (c > Columns) ? Columns : c);
                 }
                 break;
           }
        }
        else
        {
           SetAPen(&rp2, ep->BGPen);
           SetAPen(rp, ep->FGPen);
           SetBPen(rp, ep->BGPen);
           RectFill(&rp2, COL(0), ROW(i), Xbase + Xpixs - 1, ROW(i+1)-1);
           c = strlen(ptr);
           if (c)
           {
              Move(rp, COLT(0), ROWT(i));
              Text(rp, ptr, (c > Columns) ? Columns : c);
           }
        }
    }
    if (UpdateTitle)
       window_title();  /* Added by KL 2.sep.94 */
    if(!Comlinemode)
        prop_adj();
    SetBPen(rp, ep->BGPen);
}

void do_updatetitle(void)
{
   UpdateTitle = atoi(av[1]);
}

/* Changed by Karl Lukas 06/94: less flicker in conjuction with text_displayseg() */

void text_redisplay(void)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;
    int lastrow;

    if (Nsu)
        return;
    SetAPen(rp, ep->BGPen);

    lastrow = ep->Lines - ep->Topline - 1;

    if (Comlinemode)
        RectFill(rp, COL(0), ROW(Rows-1), Xbase + Xpixs - 1, Ybase + Ypixs - 1);
    else
    {
       if (lastrow < Rows)
          RectFill(rp, Xbase, ROW(lastrow), Xbase + Xpixs - 1, Ybase + Ypixs - 1);
    }
    text_displayseg(0,Rows);
}

void text_redisplaycurrline(void)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;

    int row = ep->Line - ep->Topline;

    if (Nsu)
        return;
    SetAPen(rp, ep->BGPen);
    RectFill(rp, COL(0), ROW(row), Xbase + Xpixs - 1, ROW(row+1)-1);
    text_displayseg(row, 1);
}

void text_write(unsigned char *str)
{
    short len = strlen(str);
    short i;
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;

    if (Clen + len >= 255) {
        text_sync();
        text_load();
    }
    if (ep->Insertmode == 0) {
        if (ep->Column + len >= 255)
            goto fail;
        movmem(str, Current + ep->Column, len);
        if (ep->Column + len >= Clen)
            Clen = ep->Column + len;
        Current[Clen] = 0;
    } else {
        if (Clen + len >= 255)
            goto fail;

        /* Adjust character block */
        if ((Blocktype == BLOCK_CHARACTER) && (ep->Line == BSline) && (ep->Column <= BSchar))
           BSchar += len;
        if ((Blocktype == BLOCK_CHARACTER) && (ep->Line == BEline) && (ep->Column <= BEchar))
           BEchar += len;

        movmem(Current + ep->Column, Current + ep->Column + len, Clen+1-ep->Column);
        movmem(str, Current + ep->Column, len);
        Clen += len;
        if (len < Columns - (ep->Column - ep->Topcolumn)) {
            ScrollRaster(rp, -len * Xsize, 0 ,
                COL(ep->Column - ep->Topcolumn),
                ROW(ep->Line - ep->Topline),
                Xbase + Xpixs - 1,
                ROW(ep->Line - ep->Topline + 1) - 1
            );
        }
    }
    i = (ep->Column - ep->Topcolumn + len > Columns) ? Columns - ep->Column + ep->Topcolumn : len;
    setpen(ep->Line, ep->Column);
    Move(rp, COLT(ep->Column - ep->Topcolumn), ROWT(ep->Line - ep->Topline));
    Text(rp, str, i);
    ep->Column += len;
    if (ep->Column - ep->Topcolumn >= Columns)
        text_sync();
fail:
    if (Comlinemode == 0 && ep->Wordwrap)
        do_reformat(0);
}

void do_up(void)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;

    if (ep->Line) {
        text_sync();
        --ep->Line;
        text_load();
        if (Ep->Line < Ep->Topline) {
            if (Nsu == 0) {
                ScrollRaster(rp,0,-Ysize,COL(0),ROW(0),Xbase + Xpixs - 1,ROW(Rows)-1);
                --ep->Topline;
                text_displayseg(0, 1);
            }
        }
    } else {
        Abortcommand = 1;
    }
}

void do_scrolldown(void)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;

    if (ep->Topline + Rows < ep->Lines) {
        if (Nsu == 0) {
            text_sync();
            ScrollRaster(rp,0,Ysize,COL(0),ROW(0),Xbase + Xpixs - 1,ROW(Rows)-1);
            ++ep->Topline;
            ++ep->Line;
            text_load();
            text_displayseg(Rows-1, 1);
        }
    } else {
        Abortcommand = 1;
    }
}

void do_scrollup(void)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;

    if (ep->Topline) {
        if (Nsu == 0) {
            text_sync();
            ScrollRaster(rp,0,-Ysize,COL(0),ROW(0),Xbase + Xpixs - 1,ROW(Rows)-1);
            --ep->Topline;
            --ep->Line;
            text_load();
            text_displayseg(0, 1);
        }
    } else {
        Abortcommand = 1;
    }
}

void do_down(void)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;

    if (ep->Line + 1 < ep->Lines) {
        text_sync();
        ++ep->Line;
        text_load();
        if (ep->Line - ep->Topline >= Rows) {
            if (Nsu == 0) {
                ScrollRaster(rp,0,Ysize,COL(0),ROW(0),Xbase + Xpixs - 1,ROW(Rows)-1);
                ++ep->Topline;
                text_displayseg(Rows-1, 1);
            }
        }
    } else {
        Abortcommand = 1;
    }
}


void do_downfast(void)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;

    if (ep->Line + 2 < ep->Lines) {
        text_sync();
        ep->Line += 2;
        text_load();
        if (ep->Line - ep->Topline >= Rows) {
            if (Nsu == 0) {
                ScrollRaster(rp,0,2*Ysize,COL(0),ROW(0),Xbase + Xpixs - 1,ROW(Rows)-1);
                ep->Topline += 2;
                text_displayseg(Rows-2, 2);
            }
        }
    } else {
        do_down();
    }
}

void do_upfast(void)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;
    int diff;

    if (ep->Line > 1) {
        text_sync();
        ep->Line -= 2;
        text_load();
        if ((diff = Ep->Topline - Ep->Line) > 0)
        {
            if (Nsu == 0)
            {
                ScrollRaster(rp,0,-diff*Ysize,COL(0),ROW(0),Xbase + Xpixs - 1,ROW(Rows)-1);
                ep->Topline -= diff;
                text_displayseg(0, diff);
            }
        }
    } else {
        do_up();
    }
}

/* Added by Karl Lukas 06/94 */

void scroll_jump(int newtop)
{
   ED *ep = Ep;
   RP *rp = ep->Win->RPort;
   int diff = abs(newtop - Ep->Topline);

   text_cursor(0);
   if (diff >= Rows)
   {
      text_sync();
      ep->Line += newtop - ep->Topline;
      ep->Topline = newtop;
      text_load();
      if (!text_sync())
         text_redisplay();
   }
   else if((newtop > Ep->Topline) && (Nsu == 0)) /* Scroll up */
   {
      /* Minterm 192: plain vanilla copy */
      ClipBlit(rp, COL(0), ROW(diff), rp, COL(0), ROW(0), Xpixs, (Rows-diff)*Ysize, 192);
      ep->Line += diff;
      ep->Topline = newtop;
      text_load();
      text_displayseg(Rows - diff, diff);
   }
   else if((newtop < Ep->Topline) && (Nsu == 0)) /* Scroll down */
   {
      /* Minterm 192: plain vanilla copy */
      ClipBlit(rp, COL(0), ROW(0), rp, COL(0), ROW(diff), Xpixs, (Rows-diff)*Ysize, 192);
      ep->Line -= diff;
      ep->Topline = newtop;
      text_load();
      text_displayseg(0, diff);
   }
   text_cursor(1);
}


/*
 *  PAGEUP
 *  PAGEDOWN
 *  PAGESET n   (n = 0 to 100 for percentage of #rows to scroll, minimum 1)
 *              can be > 100.
 */

void do_page(void)
{
    int n, multiplier = 1;
    ED *ep = Ep;

    switch(av[0][4]) {
    case 'u':
        multiplier = -1;
        if (ep->Topline == 0 && ep->Line == 0)  /* Added by Karl Lukas 06/94 to avoid flicker */
            return;                             /* to avoid flicker */
        if (ep->Topline == 0)
        {
           ep->Line = 0;
           text_load();
           return;
        }                                       /* KL end */
    case 'd':
        n = multiplier * Rows * Pagejump / 100;
        if (!n)
            n = multiplier;
        if (n > 0 && ep->Topline >= ep->Lines - Rows)
        {                                        /* Added by Karl Lukas 06/94      */
           if (ep->Line < (ep->Lines - 1))       /* Now the cursor really jumps to */
           {                                     /* the last line if file end is   */
              ep->Line = ep->Lines - 1;          /* reached                        */
              text_load();
           }                                     /* KL end                         */
           return;
        }
        text_sync();
        ep->Line += n;
        ep->Topline += n;
        if (ep->Line >= ep->Lines)
            ep->Line = ep->Lines - 1;
        if (ep->Line < 0)
            ep->Line = 0;
        if (ep->Topline >= ep->Lines)
            ep->Topline = ep->Lines - Rows - 1;
        if (ep->Topline < 0)
            ep->Topline = 0;
        text_load();
        if (!text_sync())
            text_redisplay();
        break;
    case 's':
        Pagejump = atoi(av[1]);
        break;
    }
}

void do_downadd(void)
{
    ED *ep = Ep;
    ubyte *ptr;

    if (ep->Line + 1 == ep->Lines) {
        ep->Modified = 1;
        if (makeroom(32) && (ptr = allocb(1))) {
            ep->List[ep->Lines] = ptr;
            *ptr = 0;
            ++ep->Lines;
        } else {
            nomemory();
        }
    }
    do_down();
}

void do_left(void)
{
    ED *ep = Ep;

    if (ep->Column) {
        --ep->Column;
        if (ep->Column < ep->Topcolumn)
            text_sync();
    } else {
        Abortcommand = 1;
    }
}

void do_right(void)
{
    ED *ep = Ep;

    if (ep->Column != 254) {
        if (Current[ep->Column] == 0) {
            Current[ep->Column] = ' ';
            Current[ep->Column+1]= '\0';
            ++Clen;
        }
        ++ep->Column;
        if (ep->Column - ep->Topcolumn >= Columns)
            text_sync();
    } else {
        Abortcommand = 1;
    }
}

void do_tab(void)
{
    short n;
    ED *ep = Ep;

    for (n = ep->Tabstop-(ep->Column % ep->Tabstop); n > 0; --n)
        do_right();
}

void do_backtab(void)
{
    short n;
    ED *ep = Ep;

    n = ep->Column % ep->Tabstop;
    if (!n)
        n = ep->Tabstop;
    for (; n > 0; --n)
        do_left();
}

void do_return(void)
{
    ubyte buf[256];
    char *partial;

    if (Comlinemode) {
        strcpy(buf, Current);
        strcpy(RecallBuf, Current);
        partial = Partial;
        Partial = NULL;
        escapecomlinemode();
        if (partial) {
            if (do_command(buf))
                do_command(partial);
            free(partial);
        } else {
            do_command(buf);
        }
    } else {
        Ep->Column = 0;
        text_sync();
        do_downadd();
    }
}

void do_bs(void)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;

    if (ep->Column)
    {
        if (Blocktype == BLOCK_CHARACTER)
        {
           if ((ep->Line == BSline) && (BSchar >= ep->Column))
              BSchar--;
           if ((ep->Line == BEline) && (BEchar + 1 >= ep->Column))
              BEchar--;
        }
        movmem(Current + ep->Column, Current + ep->Column - 1, Clen - ep->Column + 1);
        --ep->Column;
        --Clen;
        if (ep->Column < ep->Topcolumn) {
            text_sync();
        } else {
            setpen(ep->Line, ep->Topcolumn + Columns - 1);
            ScrollRaster(rp, Xsize, 0,
                COL(ep->Column - ep->Topcolumn),
                ROW(ep->Line   - ep->Topline),
                Xbase + Xpixs - 1,
                ROW(ep->Line - ep->Topline + 1)-1
            );
            if (Clen >= ep->Topcolumn + Columns) {
                setpen(ep->Line, ep->Column);
                Move(rp, COLT(Columns-1), ROWT(ep->Line - ep->Topline));
                Text(rp, Current + ep->Topcolumn + Columns - 1, 1);
            }
        }
        if (Comlinemode == 0 && ep->Wordwrap)
            do_reformat(0);
    } else {
        Abortcommand = 1;
    }
}


/*
 * esc, escimm
 */

int Savetopline, Savecolumn, Savetopcolumn;

void do_recall(void)
{
    av[0] = (ubyte *)"escimm";
    av[1] = (ubyte *)RecallBuf;
    do_esc();
}

void do_esc(void)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;

    if (Comlinemode) {
        escapecomlinemode();
        return;
    }
    text_sync();
    if (av[0][3] == 'i')
        strcpy(Current, av[1]);
    else
        Current[0] = 0;
    Clen = strlen(Current);
    Comlinemode = 1;
    returnoveride(1);
    Savetopline = ep->Topline;
    Savecolumn  = ep->Column;
    Savetopcolumn = ep->Topcolumn;
    ep->Column    = Clen;
    ep->Topcolumn = 0;
    ep->Topline   = ep->Line - Rows + 1;
    SetAPen(rp, ep->BGPen);
    RectFill(rp, COL(0), ROW(Rows-1), Xbase + Xpixs - 1, Ybase + Ypixs - 1);
    SetAPen(rp, ep->FGPen);
    Move(rp, COL(0), ROW(Rows-1) - 1);
    Draw(rp, Xbase + Xpixs - 1, ROW(Rows - 1) - 1);
    text_displayseg(Rows - 1, 1);
}

void escapecomlinemode(void)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;

    if (Partial) {
        free(Partial);
        Partial = NULL;
    }
    if (Comlinemode) {
        strcpy(RecallBuf, Current);
        Comlinemode = 0;
        returnoveride(0);
        ep->Topline = Savetopline;
        ep->Column  = Savecolumn;
        ep->Topcolumn = Savetopcolumn;
        text_load();
        SetAPen(rp, ep->BGPen);
        RectFill(rp, COL(0), ROW(Rows-1)-1, Xbase + Xpixs - 1, Ybase + Ypixs - 1);
        SetAPen(rp, ep->FGPen);
        text_displayseg(Rows - 2, 2);
    }
}

void do_del(void)
{
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;

    if (Current[ep->Column])
    {
        if (Blocktype == BLOCK_CHARACTER)
        {
           if ((ep->Line == BSline) && (BSchar > ep->Column))
              BSchar--;
           if ((ep->Line == BEline) && (BEchar >= ep->Column))
              BEchar--;
        }
        movmem(Current + ep->Column + 1, Current + ep->Column, Clen - ep->Column);
        --Clen;
        setpen(ep->Line, ep->Topcolumn + Columns - 1);
        ScrollRaster(rp, Xsize, 0,
            COL(ep->Column - ep->Topcolumn),
            ROW(ep->Line - ep->Topline),
            Xbase + Xpixs - 1,
            ROW(ep->Line - ep->Topline + 1) - 1
        );
        if (Clen >= ep->Topcolumn + Columns) {
            setpen(ep->Line, ep->Column);
            Move(rp, COLT(Columns-1), ROWT(ep->Line-ep->Topline));
            Text(rp, Current+ep->Topcolumn+Columns-1, 1);
        }
        if (Comlinemode == 0 && ep->Wordwrap)
            do_reformat(0);
    }
}

void do_top(void)
{
    text_sync();
    Ep->Line = 0;
    text_load();
    text_sync();
}

void do_bottom(void)
{
    text_sync();
    Ep->Line = Ep->Lines - 1;
    text_load();
    text_sync();
}

void do_firstcolumn(void)
{
    if (Ep->Column) {
        Ep->Column = 0;
        text_sync();
    }
}

void do_firstnb(void)
{
    for (Ep->Column = 0; Current[Ep->Column] == ' '; ++Ep->Column);
    if (Current[Ep->Column] == 0)
        Ep->Column = 0;
    text_sync();
}

void do_lastcolumn(void)
{
    short i;

    text_sync();
    i = (Comlinemode) ? Clen : strlen(Ep->List[Ep->Line]);
    if (i != Ep->Column) {
        Ep->Column = i;
        text_sync();
    }
}

/*
 * GOTO [+/-]N
 * GOTO BLOCK   start of block
 * GOTO START   start of block
 * GOTO END     end of block
 */

void do_goto(void)
{
    long n, i, col = -1;
    ubyte *ptr = av[1];

    i = 0;
    n = -1;

    switch(*ptr) {
    case 'b':
    case 's':
    case 'B':
    case 'S':
        n = -1;
        if (Ep == BEp)
        {
            n = BSline;
            col = BSchar;
        }
        break;
    case 'e':
    case 'E':
        n = -1;
        if (Ep == BEp)
        {
            n = BEline;
            col = BEchar;
        }
        break;
    case '+':
        i = 1;
    case '-':
        n = Ep->Line;
    default:
        n += atoi(ptr+i);
    }
    if (n >= Ep->Lines)
        n = Ep->Lines - 1;
    if (n < 0)
        n = 0;
    text_sync();
    Ep->Line = n;
    if ((Blocktype == BLOCK_CHARACTER) && (col >= 0))
       Ep->Column = col;
    else
       Ep->Column = 0;
    text_load();
    text_sync();
}

void do_screentop(void)
{
    text_sync();
    Ep->Line = Ep->Topline;
    text_load();
    text_sync();
}

void do_screenbottom(void)
{
    text_sync();
    Ep->Line = Ep->Topline + Rows - 1;
    if (Ep->Line < 0 || Ep->Line >= Ep->Lines)
        Ep->Line = Ep->Lines - 1;
    text_load();
    text_sync();
}

static ubyte Fstr[256];
static ubyte Rstr[256];
static short Srch_sign;
static char Doreplace;

/*
 * findstr, repstr
 */

void do_findstr(void)
{
    if (av[0][0] == 'f')
        strcpy(Fstr, av[1]);
    else
        strcpy(Rstr, av[1]);
}

/*
 * findr, nextr, prevr
 */

void do_findr(void)
{
    Doreplace = 1;
    Srch_sign = 1;
    switch(av[0][0]) {
    case 'f':
        strcpy(Fstr, av[1]);
        strcpy(Rstr, av[2]);
        break;
    case 'p':
        Srch_sign = -1;
        break;
    }
    search_operation();
}

/*
 * find, next, prev
 */

void do_find(void)
{
    Doreplace = 0;
    Srch_sign = 1;
    switch(av[0][0]) {
    case 'f':
        strcpy(Fstr, av[1]);
        break;
    case 'p':
        Srch_sign = -1;
        break;
    }
    search_operation();
}

void do_reqreplace(void)
{
   int len, i = 0, replace = 0;

   SearchPattern[0] = 0;
   ReplacePattern[0] = 0;

   len = GetClipText(SearchPattern, 255, 1);

   /* Read only to first linefeed, forget the rest */
   while ((i < len) && (SearchPattern[i] != '\n'))
      i++;
   if (SearchPattern[i] == '\n')
      SearchPattern[i] = 0;

   len = GetClipText(ReplacePattern, 255, 2);

   /* Read only to first linefeed, forget the rest */
   while ((i < len) && (ReplacePattern[i] != '\n'))
      i++;
   if (ReplacePattern[i] == '\n')
      ReplacePattern[i] = 0;

   if (! OpenReplaceWindow(Ep->Win->WScreen))
   {
      if (HandleReplaceIDCMP())
      {
         replace = 1;
      }
      else
         title("Operation cancelled");
      CloseReplaceWindow();
   }
   else
      title("Unable to open requester");

   if (replace)
   {
      PutClipText(SearchPattern, 1);
      PutClipText(ReplacePattern, 2);

      Doreplace = 1;
      Srch_sign = 1;
      ConfirmReplace = 1;
      strcpy(Fstr, SearchPattern);
      strcpy(Rstr, ReplacePattern);

      while (! Abortcommand)
         search_operation();
      ConfirmReplace = 0;
   }
}


void do_reqfind(void)
{
   char buf[256];
   int len, i = 0;

   if (ReqToolsBase)
   {
      struct TagItem taglist[] =
      {
         RT_Window, (ULONG)Ep->Win,
         TAG_DONE, 0L
      };
      buf[0] = 0;

      len = GetClipText(buf, 255, 1);

      while ((i < len) && (buf[i] != '\n')) /* Read only to first linefeed, forget the rest */
         i++;
      if (buf[i] == '\n')
         buf[i] = 0;

      if (rtGetStringA(buf, 255, "Enter search string", NULL, taglist))
      {
         PutClipText(buf, 1);
         av[0] = "f";
         av[1] = buf;
         do_find();
      }
   }
   else
      title("You need reqtools.library for this");
}

int GetClipText(char * buf, int buflen, int unit)
{
   struct IOClipReq *ior;
   struct cbbuf *clipbuf;
   int len = 0;

   if (ior = CBOpen(unit))
   {
      if (CBQueryFTXT(ior))
      {
         if (clipbuf = CBReadCHRS(ior))
         {
            len = clipbuf->count > buflen ? buflen : clipbuf->count;
            strncpy(buf, clipbuf->mem, len);
            buf[len] = 0;
            CBFreeBuf(clipbuf);
         }
         CBReadDone(ior);
      }
      CBClose(ior);
   }
   return len;
}

int PutClipText(char *buf, int unit)
{
   struct IOClipReq *ior;
   int ret = 0;

   if (ior = CBOpen(unit))
   {
      if (CBWriteFTXT(ior, buf))
         ret = 1;
      CBClose(ior);
   }
   return ret;
}


static char CaseIgnore;

void search_operation(void)
{
    int flen = strlen(Fstr);
    int rlen = strlen(Rstr);
    char senabled = 0;
    ubyte *ptr;
    int i, col;
    ED *ep = Ep;

    CaseIgnore = ep->IgnoreCase;
    text_sync();
    if (!flen) {
        title("No find pattern");
        Abortcommand = 1;
        return;
    }

    title("Searching..."); /* Added 1.sep.94 by KL */

    col = ep->Column;
    if (col >= strlen(ep->List[ep->Line]))
        col = strlen(ep->List[ep->Line]);
    for (i = ep->Line;;) {
        ptr = ep->List[i];
        if (Srch_sign > 0) {
            while (ptr[col]) {
                if (senabled && case_strncmp(Fstr,ptr+col,flen) == 0)
                    goto found;
                senabled = 1;
                ++col;
            }
            senabled = 1;
            if (++i >= ep->Lines)
                break;
            col = 0;
        } else {
            while (col >= 0) {
                if (senabled && case_strncmp(Fstr,ptr+col,flen) == 0)
                    goto found;
                senabled = 1;
                --col;
            }
            senabled = 1;
            if (--i < 0)
                break;
            col = strlen(ep->List[i]);
        }
    }
    title("Pattern Not Found");
    Abortcommand = 1;
    return;

found:
    if (! Doreplace)
       title("Found pattern"); /* Added 1.sep.94 by KL */
    ep->Line = i;
    ep->Column = col;

    text_load();
    text_sync();
    text_cursor(1);
    if (Doreplace && confirm_replace()) {
        if (rlen > flen && rlen-flen+strlen(ptr) > 254) {
            title("Replace: Line Too Long");
            Abortcommand = 1;
            return;
        }
        if (Clen-col-flen >= 0) {
            movmem(Current+col+flen, Current+col+rlen, Clen-col-flen+1);
            movmem(Rstr, Current+col, rlen);
            Clen += rlen-flen;
            ep->Column += rlen;
        }
        text_sync();
        text_redisplaycurrline();
    }
    text_cursor(0);
}

int confirm_replace(void)
{
   int ret;
   int done = 0;
   struct IntuiMessage *message;
   char buf[256];

   if (! ConfirmReplace)
      return 1;

   title("Replace? (Y)es (N)o (A)ll (Q)uit");

   while (! done)
   {
      Wait(1 << Ep->Win->UserPort->mp_SigBit);

      while (message = (struct IntuiMessage *)GetMsg(Ep->Win->UserPort))
      {
         switch (message->Class)
         {
            case RAWKEY:
               buf[0] = 0;
               DeadKeyConvert(message, buf, 255, NULL);
               switch(buf[0])
               {
                  case 'A':
                  case 'a':
                    ConfirmReplace = 0;
                  case 'Y':
                  case 'y':
                     ret = done = 1;
                     break;
                  case 'N':
                  case 'n':
                     ret = 0;
                     done = 1;
                     break;
                  case 'Q':
                  case 'q':
                     ret = 0;
                     done = 1;
                     Abortcommand = 1;
                     title("Aborted");
                     break;
                  default:
                     break;
               }
               break;
            case NEWSIZE:
               ret = 0;
               Abortcommand = 1;
               done = 1;
               set_window_params();
               if (!text_sync())
                  text_redisplay();
               title("Aborted");
               break;
            case INTUITICKS:
               break;
            default:
               break;
         }
         ReplyMsg((struct Message *)message);
      }
   }
   return ret;
}


int case_strncmp(char *s1, char *s2, int len)
{
    if (CaseIgnore == 0)
        return(strncmp(s1, s2, len));
    for (; len; --len, ++s1, ++s2) {
        if ((*s1|0x20) != (*s2|0x20))
            return(1);
        if ((!isalpha(*s1) || !isalpha(*s2)) && *s1 != *s2)
            return(1);
    }
    return(0);
}




static ubyte brackets[][2] = {
    '(',    ')',
    '{',    '}',
    '[',    ']',
    '<',    '>',
    '`',    '\'',
    0
};

void
do_findmatch()
{
    ubyte c, c2;
    ubyte *lineptr;
    short direction = 0, i;
    long cnt = 0;
    long line, column;
    long endline, endcol, col, len;

    line = Ep->Line;
    column = Ep->Column;
    c = Current[column];

    for (i = 0; brackets[i][0]; i++) {
        if (brackets[i][0] == c) {      /* forward  */
            c2 = brackets[i][1];
            direction = 1;
            endline = Ep->Lines - 1;
            break;
        }
        if (brackets[i][1] == c) {      /* backward */
            c2 = brackets[i][0];
            direction = -1;
            endline = 0;
            break;
        }
    }

    if (direction == 0) {
        title("not matchable character");
        return;
    }

    for ( ; line != endline + direction; line += direction) {

        if (cnt == 0) {
            lineptr = Current;      /* current line (we're just starting) */
            len = Clen;
            col = column;
        } else {
            lineptr = Ep->List[line];
            len = strlen(lineptr);
            col = (direction == 1) ? 0 : len - 1;
        }
        endcol = (direction == 1) ? len - 1 : 0;

        for ( ; col != endcol + direction; col += direction) {
            if (lineptr[col] == c)
                cnt++;
            else if (lineptr[col] == c2) {
                cnt--;
                if (cnt == 0) {     /* found match!!          */
                    text_sync();    /* ok, now update buffers */
                    Ep->Line = line;
                    Ep->Column = col;
                    text_load();    /* and move to new place  */
                    text_sync();
                    return;
                }
            }
        }
    }
    title("match not found");
}

/*
 *  Change to window by filepath, open new window and load new file
 *  if window cannot be found.
 */

void
do_window()
{
    ED *ed;
    char buf[128];

    if ((ed = finded(av[1], 0)) == NULL) {
        sprintf(buf, "newwindow newfile (%s)", av[1]);
        do_command(buf);
        ed = finded(av[1], 0);
    } else {
        WindowToFront(ed->Win);
        ActivateWindow(ed->Win);
    }
    if (ed == NULL) {
        title("unable to load file");
    } else {
        text_switch(ed->Win);
        if (Ep->iconmode)
            uniconify();
        else
            text_cursor(0);
    }
}

