#include <stdio.h>
/*
 * CMD2.C
 *
 *      (C)Copyright 1987 by Matthew Dillon, All Rights Reserved
 */

#include "defs.h"
#include "cb.h"
#include <ctype.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <intuition/intuition.h>
#include <libraries/gadtools.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <dos/dos.h>
#include <clib/dos_protos.h>


extern Library *GadToolsBase;

typedef struct WBStartup    WBS;
typedef struct DiskObject   DISKOBJ;

#define nomemory()  {memoryfail = 1;}

#ifndef offsetof
#define offsetof(sname,fname)   ((long)&((sname *)0)->fname)
#endif

int kill_first_line(void);
int kill_last_line(void);


#include "rexx.h"
extern int foundcmd;       /* control for implicit ARexx macro invocation   */
extern int cmderr;         /* global command error flag for do_rexx()'s use */

extern int GetNextLine(cbbuf *clipbuf, char *dest, int *index, int maxlen);
extern int CountLineFeeds(struct cbbuf *clipbuf);

extern char MForceTitle;
extern void do_bmove();

extern WBS  *Wbs;

ED *uninit_init(ED *ep)
{
    FONT  *font;
    BPTR lock = DupLock((BPTR)ep->dirlock);
    WIN *win;
    struct Gadget *gadg;
    int bufsiz = offsetof(struct _ED,EndConfig) - offsetof(struct _ED, BeginConfig);
    char *buf = malloc(bufsiz);

    movmem(&ep->BeginConfig, buf, bufsiz);
    win = ep->Win;
    font = ep->Font;
    gadg = ep->PropGad;
    ep->Font = NULL;
    text_uninit();
    text_init(Ep, NULL, NULL);
    ep = Ep;
    if (ep->Font)
        CloseFont(ep->Font);
    ep->Win = win;
    ep->Font = font;
    ep->PropGad = gadg;

    movmem(buf, &ep->BeginConfig, bufsiz);

    ep->Modified = 0;
    ep->Line = ep->Topline = 0;
    UnLock((BPTR)ep->dirlock);
    ep->dirlock = (long)lock;

    free(buf);
    return(ep);
}

void do_remeol(void)
{
    Current[Clen = Ep->Column] = 0;
    text_sync();
    text_redisplaycurrline();
}

void do_wleft(void)
{
    ED *ep = Ep;
    int i;

    for (;;) {
        i = ep->Column;
        if (i == 0)
            goto prevline;
        --i;
        while (i && Current[i] == ' ')
            --i;
        if (i == 0 && Current[0] == ' ') {
prevline:
            if (Comlinemode || ep->Line == 0) {
                i = ep->Column;
                break;
            }
            text_sync();
            --ep->Line;
            text_load();
            ep->Column = Clen;
            continue;
        }
        while (i && Current[i] != ' ')
            --i;
        if (Current[i] == ' ')
            ++i;
        break;
    }
    ep->Column = i;
    text_sync();
}

void do_wright(void)
{
    ED *ep = Ep;
    int i;

    for (;;) {
        i = ep->Column;
        if (i == Clen)
            goto nextline;
        while (i != Clen && Current[i] != ' ')  /* skip past current word */
            ++i;
        while (i != Clen && Current[i] == ' ')  /* to beg. of next word   */
            ++i;
        if (i == Clen) {
nextline:
            if (Comlinemode || ep->Line == ep->Lines - 1) {
                i = ep->Column;
                break;
            }
            text_sync();
            ++ep->Line;
            text_load();
            ep->Column = i = 0;
            if (Current[0] != ' ')
                break;
            continue;
        }
        break;
    }
    ep->Column = i;
    text_sync();
}

/* Changed 06/94 by Karl Lukas. Added handling of character based blocks */

void do_split(void)              /* split line in two at cursor pos */
{
    ubyte buf[256];
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;
    char onLastLine;
    int adj_start = 0;                                   /* KL */
    int adj_stop = 0;                                    /* KL */

    if (Blocktype == BLOCK_CHARACTER)
    {
       /* BEline will be adjusted in do_downadd() */       /* KL */
       if ((ep->Line == BEline) && (BEchar >= ep->Column)) /* KL */
       {                                                   /* KL */
          adj_stop = 1;                                    /* KL */
          BEchar -= ep->Column;                            /* KL */
       }                                                   /* KL */
       else if ((ep->Line == BSline) &&(ep->Column <= BSchar))
       {
          BSline++;
         /* adj_start = 1; */
          BSchar -= ep->Column;
       }
       else if (ep->Line == BSline - 1)
          adj_start = 1;
    }
    strcpy(buf, Current+ep->Column);
    Current[Clen = ep->Column] = '\0';
    text_sync();
    SetAPen(rp, ep->BGPen);
    if (Nsu == 0)
        RectFill(rp, COL(0), ROW(ep->Line-ep->Topline), Xbase+Xpixs-1, ROW(ep->Line-ep->Topline+1)-1);
    SetAPen(rp, ep->FGPen);
    text_displayseg(ep->Line - ep->Topline, 1);

    onLastLine = (ep->Line == ep->Lines-1);

    do_downadd();
    if (!onLastLine)
        do_insline();
    strcpy(Current, buf);
    Clen = strlen(Current);
    if (adj_start)          /* KL */ 
       BSline++;            /* KL */
    if (adj_stop)           /* KL */ 
       BEline++;            /* KL */
    text_sync();
    text_displayseg(ep->Line - ep->Topline - 1, 2);     /* Changed KL */
    do_up();
}

int do_join(void)
{
    int i = Clen, j;
    ED *ep = Ep;

    if (ep->Line + 1 < ep->Lines && strlen(ep->List[ep->Line+1])+i <= 253)
    {
        if (i && Current[i-1] != ' ')
            Current[i++] = ' ';
        strcpy(Current+i, ep->List[ep->Line+1]);
        for (j = i; Current[j] == ' '; ++j);
        for (; i >= 0 && Current[i] == ' '; --i);
        if (j > i+2)
            movmem(Current+j, Current+i+2, strlen(Current+j)+1);
        Clen = strlen(Current);
        text_sync();
        text_displayseg(ep->Line - ep->Topline, 1);
        {
            int l = text_lineno();
            do_down();
            do_deline();
            if (l != text_lineno())
                do_up();
        }
        return(1);
    }
    return(0);
}


/* do_join2() command added 06/94 by Karl Lukas */
/* Doesn't delete leading spaces of joined line */

int do_join2(void)
{
    int i = Clen, j;
    ED *ep = Ep;

    if (ep->Line + 1 < ep->Lines && strlen(ep->List[ep->Line+1])+i <= 253)
    {
        if (Blocktype == BLOCK_CHARACTER)
        {
           if ((ep->Line + 1) == BSline)
           {
              BSline--;
              BSchar += i;
           }
           else if ((ep->Line + 1) == BEline)
           {
              BEchar = BEchar + i;
              BEline--;
           }
           else if ((ep->Line == BEline) && (BEchar == i))
              BEchar--;
        }
        strcpy(Current+i, ep->List[ep->Line+1]);
        Clen = strlen(Current);
        text_sync();
        if (Blocktype != BLOCK_CHARACTER)
           text_displayseg(ep->Line - ep->Topline, 1);
        {
            int l = text_lineno();
            do_down();
            do_deline();
            if (l != text_lineno())
                do_up();
        }
        if (Blocktype == BLOCK_CHARACTER)
           text_displayseg(ep->Line - ep->Topline, 1);
        return(1);
    }
    return(0);
}


void do_margin(void)
{
    Ep->Margin = atoi(av[1]);
}

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

    if (av[1][1] == 'n')
        ep->Wordwrap = 1;
    if (av[1][1] == 'f')
        ep->Wordwrap = 0;
    if (av[1][0] == 't')
        ep->Wordwrap = 1 - ep->Wordwrap;
    if (ep->Wordwrap)
        title("Wordwrap ON");
    else
        title("Wordwrap OFF");
}

void do_setparcol(void)
{
    Ep->WWCol = atoi(av[1]);
}


/*
 * n == -1  :   force reformat entire paragraph
 * n ==  0  :   only until line equalizes (from text_write())
 *
 * What is a paragraph?   A paragraph ends whenever the left justification
 * gets larger, or on a blank line.
 */

void do_reformat(int n)
{
    char *str;
    ED *ep = Ep;
    RP *rp = ep->Win->RPort;
    int nlok, lnsc, fnst, fnsc;
    int column = ep->Column;
    int srow   = ep->Line;
    int crow   = srow;
    int erow   = srow;
    short dins = 0;         /* relative insert lines/delete lines   */
    char moded = 0;         /* any modifications done at all?       */
    char checked = 0;       /* for cursor positioning.              */

    if (ep->Margin == 0)
        ep->Margin = DefaultMargin;

    ++Nsu;
    for (;;) {
        str = (char *)ep->List[ep->Line+1];
        fnst = 0;
        fnsc = firstns(Current);
        nlok = (ep->Line + 1 < ep->Lines && fnsc >= (fnst=firstns(str)));
        if (ep->WWCol >= 0)
            fnst = fnsc = ep->WWCol;
        if (nlok && str[0] == 0)
            nlok = 0;
        lnsc = lastns(Current);
        if (lnsc < ep->Margin) {    /* space at end of line for marg-lnsc-2 letter word   */
            if (nlok == 0)        /* but no more data to joinup   */
                break;            /* done */
            if (ep->Margin - lnsc - 2 >= wordlen(str+fnst)) {
                ep->Column = 0;
                Clen = lastns(Current);
                if (Current[Clen])
                    ++Clen;
                moded = 1;
                --dins;
                if (do_join())
                    continue;
                ++dins;
                title("Error, Margin > 124");
                break;
            }
            if (n == 0)        /* if couldn't mod line, and text_write, don't update any more */
                break;
            do_down();
            erow = ep->Line;
            continue;
        }
                                /* no space, need to split      */
                                /* find start of prev word      */
        for (;;) {
            int i = lnsc;
            while (i && Current[i] != ' ')
                --i;
            lnsc = i;
            if (i >= ep->Margin) {
                while (i && Current[i] == ' ')
                    --i;
                if (i < ep->Margin)
                    break;
                lnsc = i;
                continue;
            }
            break;
        }
        if (lnsc) {             /* ok to split at word          */
            ++lnsc;
            ++dins;
            ep->Column = lnsc;
            do_split(); /* Split at point LNSC          */
            do_down();          /* must insert proper amount?   */
            {
                int indent = (nlok == 0) ? fnsc : fnst;
                if (ep->WWCol >= 0)
                    indent = ep->WWCol;
                if (!checked) {
                    checked = 1;
                    if (lnsc <= column) {   /* if split before cursor   */
                        column = column - ep->Column + indent;
                        ++crow;
                    }
                }
                if (Clen + indent < 253) {
                    movmem(Current, Current + indent, strlen(Current)+1);
                    setmem(Current, indent, ' ');
                    Clen += indent;
                }
            }
            erow = ep->Line;
            continue;
        }
        if (n == 0)
            break;
        do_down();
    }
    if (column < 0 || column > 200)
        column = 0;
    if (srow >= ep->Lines) {
        srow = ep->Lines - 1;
        goto ra;
    }
    if (dins || srow < ep->Topline || srow >= ep->Topline + Rows) {
ra:
        text_sync();
        --Nsu;
        ep->Line = crow;
        ep->Column = column;
        text_load();
        if (!text_sync())
            text_redisplay();
    } else {
        text_sync();
        --Nsu;
        ep->Line = crow;
        ep->Column = column;
        text_load();
        if (erow != srow) {
            if (!text_sync()) {
                ++erow;
                if (erow - ep->Topline > Rows)
                    erow = ep->Topline + Rows;
                SetAPen(rp, ep->BGPen);
                RectFill(rp, COL(0), ROW(srow - ep->Topline), Xbase+Xpixs-1, ROW(erow - ep->Topline)-1);
                SetAPen(rp, ep->FGPen);
                text_displayseg(srow - ep->Topline, erow - srow);
            }
        } else {
            text_sync();
            if (moded)
                text_redisplaycurrline();
        }
    }
    if (column > Clen) {
        setmem(Current+Clen, column - Clen, ' ');
        Current[column] = 0;
    }
    ep->Column = column;
}

void do_tabstop(void)
{
    Ep->Tabstop = atoi(av[1]);
}

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

    if (av[1][0]) {
        switch(av[1][1] & 0x1F) {
        case 'n'&0x1F:
            ep->Insertmode = 1;
            break;
        case 'f'&0x1F:
            ep->Insertmode = 0;
            break;
        case 'o'&0x1F:
            ep->Insertmode = 1 - ep->Insertmode;
            break;
        }
        if (ep->Insertmode)
            title("Insert mode on");
        else
            title("Insert mode off");
    }
}

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

    ep->Modified = 1;
    text_sync();
    if (makeroom(32) && (ptr = allocb(1))) {
        bmovl(ep->List+ep->Line, ep->List+ep->Line+1,ep->Lines-ep->Line);
        ep->List[ep->Line] = ptr;
        *ptr = 0;
        ++ep->Lines;
        if (BEp == ep) {
            if (ep->Line < BSline)
                ++BSline;
            if (ep->Line <= BEline)
                ++BEline;
        }
    } else {
        nomemory();
    }
    text_load();
    if (Nsu == 0)
        ScrollRaster(rp,0,-Ysize, COL(0), ROW(ep->Line-ep->Topline), COL(Columns)-1, ROW(Rows)-1);
    text_displayseg(ep->Line - ep->Topline, 1);
}

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

    strcpy(Deline, Current);
    if (ep->Lines > 1) {
        ep->Modified = 1;
        text_sync();

        FreeMem(ep->List[ep->Line], strlen(ep->List[ep->Line])+1);
        bmovl(ep->List+ep->Line+1, ep->List+ep->Line,ep->Lines-ep->Line-1);
        if (BEp == ep)
        {
            if (Blocktype == BLOCK_CHARACTER)
            {
               if (BSline == BEline && BSline == ep->Line)
               {
                  BEp = NULL;
                  BSline = BEline = BSchar = BEchar = -1;
               }
               else
               {
                  if (ep->Line < BSline)
                      --BSline;
                  else if (ep->Line == BSline)
                     BSchar = 0;
                  if (ep->Line < BEline)
                      --BEline;
                  else if (ep->Line == BEline)
                  {
                      --BEline;
                      BEchar = strlen(ep->List[BEline]);
                  }
               }
                  
            }
            else
            {
               if (ep->Line < BSline)
                   --BSline;
               if (ep->Line <= BEline)
                   --BEline;
            }
        }
        delline = ep->Line;
        if (ep->Line >= --ep->Lines) {
            --ep->Line;
            text_load();
            if (ep->Line < ep->Topline) {
                if (Nsu == 0) {
                    ep->Topline = ep->Line - (Rows>>1);
                    if (ep->Topline < 0)
                        ep->Topline = 0;
                    text_redisplay();
                }
                return;
            }
        }
        text_load();
        if (Nsu == 0)
            ScrollRaster(rp,0,Ysize, COL(0), ROW(delline-ep->Topline), COL(Columns)-1, ROW(Rows)-1);
        text_displayseg(Rows-1, 1);
    } else {
        do_firstcolumn();
        do_remeol();
        ep->Modified = 0;
    }
}

void do_chfilename(void)
{
    text_sync();
    strncpy(Ep->Name, av[1], 63);
    MForceTitle = 1;
}

void do_clear(void)  /* Added by Karl Lukas 06/94 */
{
   ED *ep = Ep;

   if (ep->Modified && getyn("Delete modified Image?") == 0)
      return;

   ep = uninit_init(ep);   
   set_window_params();
   text_load();
   text_redisplay();
}


void do_edit(void)
{
    FILE *fi;
    BPTR oldlock;
    long lines;
    ubyte buf[256];
    ubyte *ptr;
    char failed = 1;
    ED *ep = Ep;
    text_sync();
    if (*av[0] == 'n') {        /* newfile or insfile   */
        if (ep->Modified && getyn("Delete modified Image?") == 0)
            return;
        ep = uninit_init(ep);
        strncpy(ep->Name, av[1], 63);
    } else {
        ep->Modified = 1;
    }
    lines = ep->Lines;
    oldlock = CurrentDir((BPTR)ep->dirlock);

    if (fi = fopen(av[1], "r"))
    {
        int len;
        char oktitle = 1;

        setvbuf(fi, NULL, _IOFBF, 32768);  /* KL */

        title("Loading...");
        while ((len = xefgets(fi, buf, 255)) >= 0)
        {
            failed = 0;
            if (makeroom(256) && (ptr = allocb(len+1)))
            {
                ep->List[ep->Lines++] = ptr;
                movmem(buf, ptr, len+1);
            }
            else
            {
                set_window_params();
                nomemory();
                oktitle = 0;
                break;
            }
        }
        set_window_params();
        if (oktitle)
            title("OK");
        fclose(fi);
    }
    else 
    {
        title("File Not Found");
        cmderr = CMD_FAILED;
    }

    CurrentDir(oldlock);
    if (ep->Lines != 1 && lines == 1 && ep->List[0][0] == 0)
    {
        ep->Modified = 0;
        ep->Line = 0;
        FreeMem(ep->List[0], strlen(ep->List[0])+1);
        bmovl(ep->List+1, ep->List,--ep->Lines);
    }
    else
    {
        if (!failed && lines <= ep->Lines - 1)
        {
            long bsline, beline;
            short bschar, bechar;
            int oldbtype = Blocktype;
            ED *bep = BEp;

            bsline = BSline;
            beline = BEline;
            bschar = BSchar;
            bechar = BEchar;

            BEp = ep;
            BSline = lines;
            BEline = ep->Lines - 1;
            Blocktype = BLOCK_LINE;
            do_bmove();
            Blocktype = oldbtype;

            if (bep && bep != ep)
            {
                BSline = bsline;
                BEline = beline;
                bschar = BSchar;
                bechar = BEchar;
                BEp = bep;
            }
        }
    }
    set_window_params();
    text_load();
    text_redisplay();
}


/* Added by Karl Lukas 06/94 */

void do_reload(void)
{
   ED *ep = Ep;
   char name[64];

   strcpy(name, ep->Name);  /* To avoid strcpy(ep->Name, ep->Name) in do_edit() */

   av[0] = (ubyte *)"n";
   av[1] = (ubyte *)name;
   do_edit();
}



static char blockmode;

void do_appendsave(void)
{
    blockmode = 0;
    saveit("a");
}

void do_bappendsave(void)
{
    if (Blocktype == BLOCK_CHARACTER)
    {
       title("Change blocktype first");
       return;
    }
    blockmode = 1;
    saveit("a");
}

void do_bsave(void)
{
    if (Blocktype == BLOCK_CHARACTER)
    {
       title("Change blocktype first");
       return;
    }
    blockmode = 1;
    do_saveas();
}

void do_save(void)
{
    av[1] = Ep->Name;
    do_saveas();
}

void do_savetabs(void)
{
    Savetabs = (av[1][0] && av[1][1] == 'n') ? 1 : 0;
}

void do_saveas(void)
{
    saveit("w");
}

void saveit(const char *om)
{
    BPTR oldlock;
    FILE *fi;
    long i;
    short j, k;
    ubyte *ptr, *bp;
    long xs, xe;
    ubyte buf[256];
    char bm;
    ED *ep;

    bm = blockmode;
    if (blockmode && blockok()) {
        xs = BSline;
        xe = BEline + 1;
        ep = BEp;
    } else {
        xs = 0;
        xe = Ep->Lines;
        ep = Ep;
    }
    blockmode = 0;
    text_sync();
    oldlock = CurrentDir((BPTR)Ep->dirlock);
    if (Wbs && Wdisable == 0) {     /* Write out .info file */
        DISKOBJ sdo, *d;
        clrmem(&sdo, sizeof(sdo));
        if ((d = GetDiskObject(av[1])) == NULL) {
            if (getpathto(Wbs->sm_ArgList[0].wa_Lock, Wbs->sm_ArgList[0].wa_Name, buf)) {
                sdo.do_Magic = WB_DISKMAGIC;
                sdo.do_Version = WB_DISKVERSION;
                makemygadget(&sdo.do_Gadget);
                sdo.do_Type = WBPROJECT;
                sdo.do_DefaultTool = (char *)buf;
                sdo.do_ToolTypes = NULL;
                sdo.do_CurrentX = NO_ICON_POSITION;
                sdo.do_CurrentY = NO_ICON_POSITION;
                sdo.do_DrawerData = NULL;
                sdo.do_ToolWindow = NULL;
                sdo.do_StackSize = 8192;
                PutDiskObject(av[1], &sdo);
            }
        } else {
            FreeDiskObject(d);
        }
    }
    if (fi = fopen(av[1], om)) {
        setvbuf(fi, NULL, _IOFBF, 32768);  /* KL */
        title("Saving...");
        for (i = xs; i < xe; ++i) {
            ptr = ep->List[i];
            if (Savetabs) {
                for (bp = buf, j = 0; *ptr; ++ptr, ++bp, j = (j+1)&7) {
                    *bp = *ptr;
                    if (j == 7 && *bp == ' ' && *(bp-1) == ' ') {
                        k = j;
                        while (k-- >= 0 && *bp == ' ')
                            --bp;
                        *++bp = 9;
                    } else {
                        if (*bp < 32 || *bp == '\"' || *bp == '\'' || *bp == '\`' || *bp == '(')
                            break;
                    }
                }
                strcpy(bp, ptr);
                ptr = buf;
            }
            fputs(ptr, fi);
            fputc('\n', fi);
        }
        if (fclose(fi)) {
err:        Abortcommand = 1;
            title("WRITE FAILED!");
        } else {
            ep->Modified &= bm;
            title("OK");
        }
    } else {
        title("Unable to open write file");
        Abortcommand = 1;
    }
    CurrentDir(oldlock);
}

void do_block(void)          /* block, unblock   */
{
    if ((Blocktype == BLOCK_CHARACTER) && (av[0][0] != 'u'))
    {
       title("Use BSTART/BSTOP for character blocks");
       return;
    }

    text_sync();

    switch(av[0][0]) {
    case 'b':
        if (BSline < 0) {
bstart:
            BEp = Ep;
            BSline = Ep->Line;
            title("Block Begin");
        } else {
            if (BEline > -1) {
                title("Block Already Marked");
                break;
            }
            if (BEp != Ep)
                goto bstart;
            title("Block End");
            BEline = Ep->Line;
            if (BSline > BEline) {
                BEline = BSline;
                BSline = Ep->Line;
            }
            text_redrawblock(1);
        }
        break;
    case 'u':
        text_redrawblock(0);
        title ("Block Unmarked");
        break;
    }
}


int blockok(void)
{
    if (BEp && BSline >= 0 && BSline <= BEline && BEline < BEp->Lines)
        return(1);
    BEp = NULL;
    BSline = BEline = -1;
    title("Block Not Specified");
    return(0);
}

void do_bdelete(void)
{
    long n;
    ED *bep = BEp;
    WIN *savewin = Ep->Win;

    if (Blocktype == BLOCK_CHARACTER)
    {
       title("Change blocktype first");
       return;
    }
    if (blockok()) {
        text_switch(bep->Win);
        n = BEline - BSline + 1;
        if (bep->Line >= BSline && bep->Line <= BEline)
            bep->Line = BSline;
        if (bep->Line > BEline)
            bep->Line -= n;
        freelist((char **)(bep->List + BSline), BEline - BSline + 1);
        bmovl(bep->List+BEline+1,bep->List+BSline,(bep->Lines-BEline-1));
        bep->Lines -= n;
        bep->Modified = 1;
        if (bep->Line >= bep->Lines)
            bep->Line = bep->Lines - 1;
        if (bep->Line < 0)
            bep->Line = 0;
        if (bep->Lines == 0) {
            ++bep->Lines;
            bep->List[0] = allocb(1);
            bep->List[0][0] = 0;
        }
        text_load();
        BEp = NULL;
        BSline = BEline = -1;
        if (!text_sync())
            text_redisplay();
        text_switch(savewin);
    }
}


void do_bcopy(void)
{
    ubyte **list;
    long lines, i;
    ED *ep = Ep;

    if (Blocktype == BLOCK_CHARACTER)
    {
       title("Change blocktype first");
       return;
    }
    text_sync();
    if (!blockok())
        return;
    if (ep == BEp && ep->Line > BSline && ep->Line <= BEline) {
        title("Cannot Move into self");
        return;
    }
    lines = BEline - BSline + 1;
    if (extend(ep, lines)) {
        if (list = (ubyte **)allocl(lines)) {
            bmovl(BEp->List+BSline,list,lines);
            bmovl(ep->List+ep->Line, ep->List+ep->Line+lines, ep->Lines-ep->Line);
            for (i = 0; i < lines; ++i) {
                ubyte *str = allocb(strlen(list[i])+1);
                if (!str) {
                    nomemory();
                    FreeMem(list, lines * sizeof(char *));
                    freelist((char **)ep->List + Ep->Line, i);
                    bmovl(ep->List+ep->Line+lines, ep->List+ep->Line, ep->Lines-ep->Line);
                    return;
                }
                strcpy(str, list[i]);
                ep->List[ep->Line+i] = str;
            }
            FreeMem(list, lines * sizeof(char *));
        }
    }
    if (ep == BEp && ep->Line <= BSline) {
        BSline += lines;
        BEline += lines;
    }
    ep->Modified = 1;
    ep->Lines += lines;
    text_load();
    if (!text_sync())
        text_redisplay();
}


void do_bmove(void)
{
    long lines;
    ubyte **list;
    ED *ep = Ep;

    if (Blocktype == BLOCK_CHARACTER)
    {
       title("Change blocktype first");
       return;
    }
    text_sync();
    if (!blockok())
        return;
    if (BEp == ep && ep->Line >= BSline && ep->Line <= BEline) {
        title("Cannot Move into self");
        return;
    }
    lines = BEline - BSline + 1;
    if (!(list = (ubyte **)allocl(lines))) {
        nomemory();
        return;
    }
    BEp->Modified = ep->Modified = 1;
    bmovl(BEp->List + BSline, list, lines);
    if (ep == BEp) {
        if (ep->Line > BSline) {
            bmovl(ep->List+BEline+1, ep->List+BSline, ep->Line-BEline-1);
            bmovl(list, ep->List + ep->Line - lines, lines);
        } else {
            bmovl(ep->List+ep->Line, ep->List+ep->Line+lines, BSline-ep->Line);
            bmovl(list, ep->List + ep->Line, lines);
        }
    } else {
        WIN *savewin = ep->Win;
        if (extend(ep, lines)) {
            bmovl(BEp->List+BEline+1, BEp->List+BSline, BEp->Lines-BEline-1);
            bmovl(ep->List+ep->Line, ep->List+ep->Line+lines, ep->Lines-ep->Line);
            bmovl(list, ep->List+ep->Line, lines);
            ep->Lines += lines;
            BEp->Lines -= lines;
            if (BEp->Line >= BSline && BEp->Line <= BEline)
                BEp->Line = BSline - 1;
            if (BEp->Line > BEline)
                BEp->Line -= lines;
            if (BEp->Line < 0)
                BEp->Line = 0;
            BSline = BEline = -1;
            if (BEp->Lines == 0) {
                ubyte *ptr = allocb(1);
                BEp->List[0] = ptr;
                *ptr = 0;
                ++BEp->Lines;
            }
            text_load();
            text_switch(BEp->Win);
            BEp = NULL;
            ep = Ep;
            if (!ep->iconmode) {
                if (!text_sync())
                    text_redisplay();
            }
            text_switch(savewin);
            ep = Ep;
        }
    }
    BSline = BEline = -1;
    BEp = NULL;
    FreeMem(list, lines * sizeof(char *));
    ep->Modified = 1;
    text_load();
    if (!text_sync())
        text_redisplay();
}


/*
 * IF condition trueaction, IFELSE condition trueaction falseaction
 *
 *  condition:  !condition NOT the specified condition.
 *              #          toggle number is SET
 *              top        top of file (on first line)
 *              bot        end of file (on last line)
 *              left       start of line (leftmost column)
 *              right      end of line (nothing but spaces under and to the right)
 *              modified   text has been modified
 *              insert     currently in insert mode
 *              y[<=>]#    cursor is (any OR combo of <,>,=) row #  (line numbers start at 1)
 *              x[<=>]#    cursor is (<,>,<=,>=,<>) column #        (columns start at 1)
 *                          <> means 'not equal'
 *
 *              cl         char under cursor is lower case
 *              cu         char under cursor is upper case
 *              ca         char under cursor is alpha
 *              cn         char under cursor is numeric
 *              cb         char within selected block
 *              c[<=>]#    char under cursor is (combo of <,>,and =) #
 */

void do_if(void)
{
    char haselse = (av[0][2] == 'e');
    char iswhile = (av[0][0] == 'w');
    char istrue, notop = 0;
    char c, cx, cc;
    ubyte *buf1, *buf2;
    ubyte *ptr;
    ED *ep = Ep;
    int i, cxn, cn;

    buf1 = (ubyte *)malloc(256);
    buf2 = (ubyte *)malloc(256);
    if (buf1 == NULL || buf2 == NULL) {
        if (buf1) free(buf1);
        if (buf2) free(buf2);
        title("No Memory!");
        return;
    }
    breakreset();
    ptr = av[1];
    if (*ptr == '!') {
        notop = 1;
        ++ptr;
    }
    c = ptr[0];
    cn= atoi(ptr);
    cx= ptr[1];
    cxn=atoi(ptr+1);
    strcpy(buf1, av[2]);

loop:
    istrue = 0;
    i = 0;
    switch(c) {
    case 'x':
        i = ep->Column + 1;
    case 'y':
        if (!i)
            i = ep->Line + 1;
conditional:
        {
            int j, n;
            char any = 0;

            for (j = 1; ptr[j] && !isdigit(ptr[j]); ++j);
            n = atoi(ptr+j);
            for (j = 1; ptr[j]; ++j) {
                switch(ptr[j]) {
                case '<':
                    any = 1;
                    if (i < n)
                        istrue = 1;
                    break;
                case '=':
                    any = 1;
                    if (i == n)
                        istrue = 1;
                    break;
                case '>':
                    any = 1;
                    if (i > n)
                        istrue = 1;
                    break;
                }
            }
            if (!any && i == n)  /* default is equivalence   */
                istrue = 1;
        }
        break;
    case 't':
        istrue = ep->Line == 0;
        break;
    case 'b':
        istrue = ep->Line == ep->Lines-1;
        break;
    case 'l':
        istrue = ep->Column == 0;
        break;
    case 'r':
        istrue = ep->Column == Clen;
        break;
    case 'm':
        text_sync();
        istrue = ep->Modified != 0;
        break;
    case 'e':
        istrue = Comlinemode != 0;
        break;
    case 'i':
        istrue = ep->Insertmode != 0;
        break;
    case 'c':
        cc = Current[ep->Column];
        switch(cx) {
        case 'b':
            istrue = BEp == ep && ep->Line >= BSline && ep->Line <= BEline;
            break;
        case 'l':
            istrue = islower(cc);
            break;
        case 'u':
            istrue = isupper(cc);
            break;
        case 'a':
            istrue = isalnum(cc);
            break;
        case 'n':
            istrue = isdigit(cc);
            break;
        default:                /* c[<=>]#  */
            i = Current[ep->Column];
            goto conditional;
            break;
        }
        break;
    default:
        if (isdigit(c))
            istrue = do_toggle(cn) != 0;
        else
            title("bad conditional");
        break;
    }
    istrue ^= notop;
    if (istrue) {
        strcpy(buf2, buf1);     /* could be executed multiple times */
        if (do_command(buf2) == 0)
            goto done;
        if (iswhile) {
            if (breakcheck())
                Abortcommand = 1;
            else
                goto loop;
        }
    } else {
        if (haselse) {          /* only executed once */
            strcpy(buf2, av[3]);
            do_command(buf2);
        }
    }
done:
    free(buf1);
    free(buf2);
}


/*
 * TOGGLE #, SETTOGGLE #, RESETTOGGLE #
 */

int do_toggle(int n)
{
    static char tg[MAXTOGGLE];
    int i;

    if (n >= 0) {
        if (n >= MAXTOGGLE)
            return(0);
        return((int)tg[n]);
    }
    i = atoi(av[1]);
    if (i >= 0 && i < MAXTOGGLE) {
        switch(av[0][0]) {
        case 't':
            tg[i] = !tg[i];
            break;
        case 's':
            tg[i] = 1;
            break;
        case 'r':
            tg[i] = 0;
            break;
        }
    }
}


void do_tlate(void)
{
    ubyte *ptr = av[1];
    ED *ep = Ep;
    char c = Current[ep->Column];

    if (c == 0)
        c = ' ';
    if (ptr[0] == '+')
        c += atoi(ptr+1);
    else
    if (ptr[0] == '-')
        c -= atoi(ptr+1);
    else
        c = atoi(ptr);
    if (c) {
        if (Current[ep->Column] == 0) {
            Clen = ep->Column + 1;
            Current[Clen] = 0;
        }
        Current[ep->Column] = c;
        if (Nsu == 0) {
            movetocursor();
            setpen(ep->Line, ep->Column);
            Text(ep->Win->RPort, Current+ep->Column, 1);
        }
    }
}

/*
 *  BSOURCE
 *
 *  note that since the start and end lines are loaded immediately and the
 *  block unblock'd before execution starts, you can theoretically have
 *  another BSOURCE as part of this BSOURCE (but be carefull!).
 */

void do_bsource(void)
{
    ubyte buf[256];
    int i, sl, se;

    if (Blocktype == BLOCK_CHARACTER)
    {
       title("Change blocktype first");
       return;
    }
    if (blockok()) {
        sl = BSline;
        se = BEline + 1;
        for (i = sl; BEp && i < se && i < BEp->Lines; ++i) {
            text_sync();        /* make sure we are using latest text */
            strcpy(buf, BEp->List[i]);
            if (buf[0] != '#' && do_command(buf) == 0)
                break;
        }
        text_redrawblock(0);
    }
}

/*
 *  SCANF controlstring
 *
 *  The C scanf routine.  Only one variable, a string, is allowed in the
 *  control string.
 */

void do_scanf(void)
{
    char buf[256];

    buf[0] = 0;
    sscanf(Current+Ep->Column,av[1],buf,buf,buf,buf,buf,buf,buf);
    if (String)
        free(String);
    String = (char *)malloc(strlen(buf)+1);
    strcpy(String,buf);
    title(String);
}

void movetocursor(void)
{
    ED *ep = Ep;
    Move(ep->Win->RPort, XTbase+(ep->Column-ep->Topcolumn)*Xsize, YTbase+(ep->Line-ep->Topline)*Ysize);
}

int extend(ED *ep, int lines)
{
    long extra = ep->Maxlines - ep->Lines;
    ubyte **list;

    if (lines > extra) {
        lines += ep->Lines;
        if (list = (ubyte **)allocl(lines)) {
            bmovl(ep->List, list, ep->Lines);
            FreeMem(ep->List, sizeof(char *) * ep->Maxlines);
            ep->Maxlines = lines;
            ep->List = list;
            return(1);
        }
        nomemory();
        return(0);
    }
    return(1);
}

int makeroom(int n)
{
    ED *ep = Ep;
    if (ep->Lines >= ep->Maxlines)
        return(extend(ep, n));
    return(1);
}

void freelist(char **list, int n)
{
    int window = 0, number = n;

    if (n > 2000)
       window = OpenProgressWindow("Freeing memory");

    while (n) {
        if (window)
           UpdateProgressWindow((number - n), number, 4);
        FreeMem(list[0], strlen(list[0])+1);
        ++list;
        --n;
    }
   if (window)
      CloseProgressWindow();
   if (FlushMem)
      Execute("C:Flush >NIL:", NULL, NULL);
}

void do_noflushmem(void)
{
   FlushMem = 0;
   title("Flush turned off");
}

void do_blocktype(void)
{
   char buf[256];

   switch (av[1][0])
   {
      case 'l' :
      case 'L' :
         Blocktype = BLOCK_LINE;
         text_redrawblock(0);
         title("Blocktype line");
         break;
      case 'c' :
      case 'C' :
         Blocktype = BLOCK_CHARACTER;
         text_redrawblock(0);
         title("Blocktype character");
         break;
      case 'v' :
      case 'V' :
         Blocktype = BLOCK_VERTICAL;
         text_redrawblock(0);
         title("Blocktype vertical");
         break;
      default:
         sprintf(buf, "Illegal blocktype: %s", av[1]);
         title(buf);
         break;
   }
}


void do_bstart(void)
{


   ED *ep = Ep;

   Blockempty = 0;

   Marking = 1;
   text_sync();
   switch (Blocktype)
   {
      case BLOCK_LINE:
         BEp = ep;
         BSline = ep->Line;
         if ((BSline > BEline) && (BEline >= 0))
         {
            long tmp = BSline; BSline = BEline; BEline = tmp;
         }
         if ((BSline >= 0) && (BEline >= 0))  /* There is a valid block */
            text_redrawblock(1);
         title("line block start");
         BSchar = BEchar = -1;
         break;
      case BLOCK_CHARACTER:
         BEp = ep;
         BSline = initialBSline = ep->Line;
         BSchar = initialBSchar = ep->Column;
         if ((BSline == BEline) && (BSchar == BEchar))
         {
            Blockempty = 1;
            /* Empty blocks are now allowed */
         }
         else if ((BSline > BEline) && (BEline >= 0))
         {
            short tp;
            long tmp = BSline; BSline = BEline; BEline = tmp;
            tp = BSchar; BSchar = BEchar; BEchar = tp;
         }
         else if ((BSline == BEline) && (BSchar > BEchar))
         {
            short tp = BSchar; BSchar = BEchar; BEchar = tp;
         }
         if ((BSline >= 0) && (BEline >= 0))  /* There is a valid block */
            text_redrawblock(1);


         title("character block start");
         break;
      case BLOCK_VERTICAL:
         title("Not implemented yet");
         break;
   }
}

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

   if (BEp == ep)
   {
      text_sync();
      Blockempty = 0;
      Marking = 0;
      switch (Blocktype)
      {
         case BLOCK_LINE:
            if (BSline >= 0)
            {
               BEline = ep->Line;
               if (BSline > BEline)
               {
                  long tmp = BSline; BSline = BEline; BEline = tmp;
               }
               /* There is a valid block */
               text_redrawblock(1);
               title("block end");
               BSchar = BEchar = -1;
            }
            else
               title("Got to start block first");
            break;
         case BLOCK_CHARACTER:
            if (BSline >= 0)
            {
               BEline = ep->Line;
               BEchar = ep->Column;
               if ((BEline > initialBSline) || ((BEline == initialBSline) && (BEchar > initialBSchar)))
               {
                  BSline = initialBSline; BSchar = initialBSchar;
               }
               if ((BSline == BEline) && (BSchar == BEchar))
               {
                  Blockempty = 1;
                  /* Empty blocks are now allowed */
               }
               else if ((BSline > BEline) && (BEline >= 0)) /* bend before bstart position */
               {
                  short tp;
                  long tmp = BSline; BSline = BEline; BEline = tmp;
                  tp = BSchar; BSchar = BEchar; BEchar = tp;
               }
               else if ((BSline == BEline) && (BSchar > BEchar)) /* bend before bstart position */
               {
                  short tp = BSchar; BSchar = BEchar; BEchar = tp;
               }
               else /* bend after bstart position  at least one byte */
               {
                  if (--BEchar < 0)
                  {
                     BEline--; /* This might result in an empty block, which is legal now */
                     BEchar = strlen((char *)ep->List[BEline]);
                  }
               }

               if ((BEline < initialBSline) || ((BEline == initialBSline) && (BEchar < initialBSchar)))
               {
                  BEline = initialBSline; BEchar = initialBSchar;
               }

               if ((BSline >= 0) && (BEline >= 0))  /* There is a valid block */
                  text_redrawblock(1);

               title("character block end");
            }
            else
               title("Got to start block first");


            break;
         case BLOCK_VERTICAL:
            title("Not implemented yet");
            break;
      }
   }
   else
   {
      text_redrawblock(0);
      title("Got to start block first");;
   }
}


/* This only works if CountLineFeeds() was called on clipbuf */
/* clipbuf->mem may not contain anymore linefeeds            */

int GetNextLine(cbbuf *clipbuf, char *dest, int *index, int maxlen)
{
   char ebuf[256];

   int i = 0, num = clipbuf->count;
   char *source = clipbuf->mem + *index;

   if ((*index) >= num)
      return (-1);

   while (((*index + i) < num) && (source[i]))
      i++;

   *index = *index + i + 1;

   if (source[i] == '\n')
      source[i] = 0;

   return detab(source, dest, maxlen);
}


/* 1.9.94 Einige kleine Verbesserungen angebracht:
 *        do_paste hat irrtuemlich eine Leerzeile im Text geloescht,
 *        wenn diese unmittelbar nach dem gepasteten Text kam.
 *        Der Cursor wird nun auf die erste Poisition nach dem
 *        gepasteten Text gesetzt.
 *        Die Veraenderungen sind mit <-- gekennzeichnet
 */

void do_paste(void)
{
   ED *ep = Ep;
   struct IOClipReq *ior;
   struct cbbuf *clipbuf;
   int index = 0;
   int lines, len, i;
   char buf[256];
   char endbuf[256];
   char *str;
   int window = 0;
   int newcol = 0;

   text_sync();
   if (ior = CBOpen(0))
   {
      if (CBQueryFTXT(ior))
      {
         if (clipbuf = CBReadCHRS(ior))
         {
            ep->Modified = 1;
            if (BEp && ep->Line >= BSline && ep->Line <= BEline)
            {
               text_redrawblock(0);
            }
            lines = CountLineFeeds(clipbuf);
            if (lines > 1500)
               window = OpenProgressWindow("Pasting");

            if (lines && BEp && ep->Line < BSline)
            {
               BSline += lines;
               BEline += lines;
            }
            len = GetNextLine(clipbuf, buf, &index, 256);
            if (lines)
            {
               if ((lines > 1) && (ep->Column == strlen(Current)) &&
                   (ep->Column > 0) &&  /* <-- */
                   (clipbuf->mem[clipbuf->count - 1] == 0))
                  lines--;

               str = (char *)allocb(ep->Column + 2 + len);
               strcpy(endbuf, ep->List[ep->Line] + ep->Column);
            }
            else
            {
               str = (char *)allocb(strlen(Current) + len + 1);
               newcol = ep->Column + len;
            }
            if (str)
            {
               if (lines)
               {
                  strncpy(str, Current, ep->Column);
                  strcpy(str + ep->Column, buf);
               }
               else
               {
                  strcpy(str, Current);
                  strins(str + ep->Column, buf);
               }
               FreeMem(ep->List[ep->Line], strlen(ep->List[ep->Line])+1);
               if (strlen(str) > 255)
               {
                  strncpy(buf, str, 255);
                  buf[255] = 0;
                  FreeMem(str, strlen(str));
                  str = (char *)allocb(256);
                  strncpy(str, buf, 256);
                  title("Line truncated");
               }
               ep->List[ep->Line] = str;
               if (lines)
               {
                  extend(ep, lines);
                  bmovl(ep->List + ep->Line + 1, ep->List + ep->Line + lines + 1,
                        ep->Lines - ep->Line - 1);
                  ep->Lines += lines;
                  ep->Modified = 1;

                  for (i = 1; i < lines; i++)
                  {
                     len = GetNextLine(clipbuf, buf, &index, 256);
                     str = (char *)allocb(strlen(buf) + 1);
                     if (str)
                     {
                        strcpy(str, buf);
                        ep->List[ep->Line + i] = str;
                     }
                     else
                     {
                        nomemory();
                        break;
                     }
                     if (window)
                        UpdateProgressWindow(i, lines, 4);
                  }
                  len = GetNextLine(clipbuf, buf, &index, 256);
                  str = (char *)allocb(strlen(buf) + strlen(endbuf) + 1);
                  if (str)
                  {
                     if (len >= 0)
                        newcol = strlen(buf);
                     if (len >= 0)
                        strcpy(str, buf);
                     else
                        buf[0] = 0;
                     strcat(str, endbuf);
                     if (strlen(str) > 255)
                     {
                        strncpy(buf, str, 255);
                        buf[255] = 0;
                        FreeMem(str, strlen(str));
                        str = (char *)allocb(256);
                        strncpy(str, buf, 256);
                        title("Line truncated");
                     }
                     ep->List[ep->Line + lines] = str;
                  }
                  else
                     nomemory();
                  text_load();
                  text_displayseg(ep->Line - ep->Topline, Rows - (ep->Line - ep->Topline));

                  ep->Line += lines;
                  ep->Column = newcol;

                  text_load();
                  text_sync();
               }
               else
               {
                  ep->Column = newcol;
                  text_load();
                  text_displayseg(ep->Line - ep->Topline, 1);
               }
            }
            else
               nomemory();

            CBFreeBuf(clipbuf);
         }
         else
            title("Cannot read clipboard");
         CBReadDone(ior);
      }
      else
         title("Clipboard is empty");
      CBClose(ior);
   }
   else
      title("ERROR: Can't open clipboard device");
   if (window)
      CloseProgressWindow();
}

/* Counts linefeeds in clipbuf and sets them to zero */
int CountLineFeeds(struct cbbuf *clipbuf)
{
   int i;
   int count = 0;
   char *buf = clipbuf->mem;

   for (i = 0; i < clipbuf->count; i++)
      if (*buf++ == '\n')
      {
         *(buf - 1) = 0;
         count++;
      }

   return count;
}

void do_copy(void)
{
   ED *ep = BEp;
   struct IOClipReq *ior;
   char *str;
   int buflen;

   if (blockok() && ! Blockempty)
   {
      text_sync();
      if (str = block_to_str(&buflen))
      {
         if (ior = CBOpen(0L))
         {
            if (! CBWriteFTXT(ior, str))
               title("Can't write to clipboard");
            else
            {
               text_redrawblock(0);
               title("Block copied to clip");
            }
            CBClose(ior);
         }
         else
            title("Can't open clipboard");
         FreeMem(str, buflen);
      }
      else
         title("No memory - Cannot copy block");
   }
   else
      title("Gotta mark a block first");
}


/* Watch out: There MUST be a valid block for this */

char *block_to_str(int *buflen)
{
   ED *ep = BEp;
   int lines, i, count = 2;
   char *str, *ptr;

   if (Blocktype != BLOCK_LINE && Blocktype != BLOCK_CHARACTER)
      return 0;

   lines = BEline - BSline + 1;


   for (i = 0; i < lines; i++)
      count += (strlen(ep->List[BSline + i]) + 1);

   *buflen = count;
   str = (char *)allocb(count);
   if (str)
   {
      ptr = str;
      if (Blocktype == BLOCK_CHARACTER)
      {
         if (lines == 1)
         {
            strncpy(ptr, ep->List[BSline] + BSchar, BEchar - BSchar + 1);
            *(ptr + (BEchar - BSchar + 1)) = 0;
         }
         else
            strcpy(ptr, ep->List[BSline] + BSchar);
      }
      else
         strcpy(ptr, ep->List[BSline]);
      ptr += strlen(ptr);
      *ptr++ = '\n';
      if (lines > 1)
      {
         for (i = 1; i < lines; i++)
         {
            strcpy(ptr, ep->List[BSline + i]);
            ptr += strlen(ptr);
            *ptr++ = '\n';
         }
         if (Blocktype == BLOCK_CHARACTER)
         {
            i = strlen(ep->List[BEline]);
            if (i > BEchar)
            {
              ptr -= (i - BEchar);
              *ptr++ = '\n';
            }
         }
      }
      if (Blocktype == BLOCK_CHARACTER && BEchar < strlen(ep->List[BEline]))
      {
         *(--ptr) = 0;
      }
      else
         *ptr = 0;
   }
   return str;
}


/***********************************************************************************************/

struct Window *ProgressWnd = NULL;
struct Screen         *Scr = NULL;
APTR            VisualInfo = NULL;
UWORD offx, offy;

void do_progresswnd(void)
{
   ProgressWindow = atoi(av[1]);
}

void ProgressRender(void)
{
    offx = ProgressWnd->BorderLeft;
    offy = ProgressWnd->BorderTop;


    DrawBevelBox( ProgressWnd->RPort, offx + 9, offy + 4, 204, 15, GT_VisualInfo, VisualInfo, GTBB_Recessed, TRUE, TAG_DONE );
    DrawBevelBox( ProgressWnd->RPort, offx + 10, offy + 5, 202, 13, GT_VisualInfo, VisualInfo, TAG_DONE );
}

int OpenProgressWindow(char *title)
{
    UWORD offx, offy;

    if (! GadToolsBase)
       return 0;
    if (! ProgressWindow)
       return 0;
    if ( ! ( Scr = LockPubScreen((UBYTE * )"Workbench" )))
       return 0;
    if ( ! ( VisualInfo = GetVisualInfo( Scr, TAG_DONE )))
        return 0;
    offx = Scr->WBorLeft,offy = Scr->WBorTop + Scr->RastPort.TxHeight + 1;

    if ( ! ( ProgressWnd = OpenWindowTags( NULL,
                    WA_Left,          Ep->Win->LeftEdge + (Ep->Winwidth / 2) - 115,
                    WA_Top,           Ep->Win->TopEdge + (Ep->Winheight / 3) - 16,
                    WA_Width,         230,
                    WA_Height,        26 + offy,
                    WA_IDCMP,         0,
                    WA_Flags,         WFLG_DRAGBAR|WFLG_SMART_REFRESH,
                    WA_Title,         title,
                    WA_PubScreen,     Scr,
                    TAG_DONE )))
        return 0;

    ProgressRender();
    SetAPen(ProgressWnd->RPort, 3);

    return 1;
}

void CloseProgressWindow( void )
{
    if ( ProgressWnd        ) {
        CloseWindow( ProgressWnd );
        ProgressWnd = NULL;
    }
    if ( VisualInfo ) {
        FreeVisualInfo( VisualInfo );
        VisualInfo = NULL;
    }
    if ( Scr        ) {
        UnlockPubScreen( NULL, Scr );
        Scr = NULL;
    }
}

void UpdateProgressWindow(int done, int total, int step)
{
   int percent = 100 * done / total;

   if (step <= 0) step = 1; /* avoid division by 0 */

   if ((percent % step == 0) && ProgressWnd && percent >= 0 && percent <=100)
   {
      RectFill(ProgressWnd->RPort, offx + 11,
                                   offy + 6, offx + 11 + percent * 2, offy + 16);
   }
}

/***********************************************************************************/

void do_cut(void)
{
   ED *ep = BEp;
   char *str;
   char buf[256];
   WIN *savewin = Ep->Win;
   int start, stop, lines;
   int bsc = BSchar;
   int bsl = BSline;
   int bec = BEchar;
   int bel = BEline;

   char join1 = 0, join2 = 0;

   if (blockok() && ! Blockempty)
   {
      ep->Modified = 1;
      if (Blocktype == BLOCK_CHARACTER)
      {
         text_sync();
         text_switch(ep->Win);
         text_sync();
         do_copy();

         BSchar = bsc; BSline = bsl; BEchar = bec; BEline = bel;
         BEp = ep;

         if (kill_first_line())
            start = BSline;
         else
         {
            join1 = 1;

            start = BSline + 1;

            if (BSchar > 0)
               strncpy(buf, ep->List[BSline], BSchar);
            if (BEline == BSline)
               strcpy(buf + BSchar, ep->List[BSline] + BEchar + 1);
            else
               buf[BSchar] = 0;
            str = (char *)allocb(strlen(buf) + 1);
            if (str)
            {
               strcpy(str, buf);
               FreeMem(ep->List[BSline], strlen(ep->List[BSline]) + 1);
               ep->List[BSline] = str;
            }
            else
               nomemory();
         }
         if (kill_last_line())
         {
            stop = BEline;
         }
         else
         {
            stop = BEline - 1;

            if (BEline != BSline)
            {
               join2 = 1;

               strcpy(buf, ep->List[BEline] + BEchar + 1);
               str = (char *)allocb(strlen(buf) + 1);
               if (str)
               {
                  strcpy(str, buf);
                  FreeMem(ep->List[BEline], strlen(ep->List[BEline]) + 1);
                  ep->List[BEline] = str;
               }
               else
                  nomemory();
            }
         }
         lines = stop - start + 1;

         if (lines > 0)
         {
            int oldblocktype = Blocktype;
            Blocktype = BLOCK_LINE;
            BSline = start; BEline = stop;
            text_load();
            text_switch(savewin);
            do_bdelete();
            Blocktype = oldblocktype;
            text_load();
         }
         else
         {
            text_load();
            text_redrawblock(0);
            text_switch(savewin);
            text_load();
         }
         if (join1 && join2)
         {
            do_command("up");
            do_command("join2");
            do_command("if r last");
         }
      }
      else
      {
         do_copy();
         BEp = ep;
         BSchar = bsc; BSline = bsl; BEchar = bec; BEline = bel;
         do_bdelete();
      }
   }
   else
      title("Gotta mark a block first");
}


int kill_first_line(void)
{
   ED *ep = BEp;

   if (BSchar == 0)
   {
      if ((BSline == BEline) && (BEchar >= strlen(ep->List[BSline])))
         return 1;
      if (BSline != BEline)
         return 1;
   }
   return 0;
}

int kill_last_line(void)
{
   ED *ep = BEp;

   /*  if (BEchar >= strlen(ep->List[BSline])) */
   if (BEchar >= strlen(ep->List[BEline]))
   {
      if ((BSline == BEline) && (BSchar == 0))
         return 1;
      if (BSline != BEline)
         return 1;
   }
   return 0;
}


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

   if (BEp == ep)
   {
      text_sync();
      Blockempty = 0;
      switch (Blocktype)
      {
         case BLOCK_LINE:
            if (BSline >= 0)
            {
               BEline = ep->Line;
               if (BSline > BEline)
               {
                  long tmp = BSline; BSline = BEline; BEline = tmp;
               }
            }
            break;
         case BLOCK_CHARACTER:
            if (BSline >= 0)
            {
               BEline = ep->Line;
               BEchar = ep->Column;
               if ((BEline > initialBSline) || ((BEline == initialBSline) && (BEchar > initialBSchar)))
               {
                  BSline = initialBSline; BSchar = initialBSchar;
               }
               if ((BSline == BEline) && (BSchar == BEchar))
               {
                  Blockempty = 1;
                  /* Empty blocks are now allowed */
               }
               else if ((BSline > BEline) && (BEline >= 0)) /* bend before bstart position */
               {
                  short tp;
                  long tmp = BSline; BSline = BEline; BEline = tmp;
                  tp = BSchar; BSchar = BEchar; BEchar = tp;
               }
               else if ((BSline == BEline) && (BSchar > BEchar)) /* bend before bstart position */
               {
                  short tp = BSchar; BSchar = BEchar; BEchar = tp;
               }
               else /* bend after bstart position  at least one byte */
               {
                  if (--BEchar < 0)
                  {
                     BEline--; /* This might result in an empty block, which is legal now */
                     BEchar = strlen((char *)ep->List[BEline]);
                  }
               }

               if ((BEline < initialBSline) || ((BEline == initialBSline) && (BEchar < initialBSchar)))
               {
                  BEline = initialBSline; BEchar = initialBSchar;
               }
               
            }

            break;
         case BLOCK_VERTICAL:
            title("Not implemented yet");
            break;
      }
   }
}
