/*-- AutoRev header do NOT edit!
*
*   Program         :   main.c
*   Copyright       :   © 1991 Jaba Development
*   Author          :   Jan van den Baard
*   Creation Date   :   21-Apr-91
*   Current version :   1.5
*   Translator      :   DICE v2.6
*
*   REVISION HISTORY
*
*   Date          Version         Comment
*   ---------     -------         ------------------------------------------
*   17-Sep-91     1.5             Changed input-handler to commodity broker.
*   16-Sep-91     1.4             Added mini line editor.
*   16-Sep-91     1.4             Added text save option.
*   16-Sep-91     1.4             Added pattern gadget in FileRequesters.
*   23-Aug-91     1.3             View now support ECS screen modes.
*   12-Aug-91     1.2             Added Save text block option.
*   12-Aug-91     1.2             Search now from top-line.
*   03-Jul-91     1.1             Removed Enforcer hits!
*   03-Jul-91     1.1             Fixed bug in decrunch routine!
*   21-Apr-91     1.0             View main program. OS 2 ONLY!
*
*-- REV_END --*/

#include "view.h"

/*
 * Function proto-types.
 */
long OpenConsole( void );
void CloseConsole( void );
void Quit( long );
void Inform( char * );
void Display( struct Line * );
void CheckDir( UBYTE * );
void LoadFile( long );
void DisplayText( void );
void MoveTo( UBYTE, UBYTE );
void LineDown( void );
void LineUp( void );
void Top( void );
void Bottom( void );
void PageUp( void );
void PageDown( void );
void Percentage( void );
void BytesShown( void );
void InfoLine( void );
void ErrorLine( UBYTE * );
void WaitKey( void );
void Help( void );
long CountEsc( struct Line *, long );
void DoFound( void );
void PrintFound( UWORD );
void GetSomething( ULONG );
void FindN( void );
void FindP( void );
void EditFile( void );
void PrintFile( void );
__geta4 void PrintProc( void );
long IsItADir( void );
long CheckPP( void );
long CheckBlock( UWORD );
long ParseName( char * );
void SetMark( UWORD );
void UnSetMark( UWORD );
void JumpMark( UWORD );
void SaveBlock( WORD );
void EditLine( void );
void SetupComm( void );
void QuitComm( void );
void OpenLibs( void );
void OpenDisplay( void );
void CloseDisplay( void );
void GetRequest( void );
void MainLoop( void );
void myMain( BOOL );

/*
 * External function proto-types.
 */
extern void _waitwbmsg( void );
extern void _exit( int );
extern void ConvertKeyTab( void );
extern void HandleKeyboard( UWORD, UWORD );
extern long HandleMsg( struct MsgPort * );
extern void ClearMsg( struct MsgPort * );

/*
 * Macros.
 */
#define MAXCOL(w,f)     (w->Width  / f->tf_XSize)
#define CLRLIN()        SetAPen(VW_rport,2); RectFill(VW_rport,0,0,VW_wnd->Width,VW_font->tf_YSize-1);
#define CLRBLK()        setmem(&VW_blk[0],(10*sizeof(struct TextBlock)),0);
#define CxOn(b)         ActivateCxObj(b,TRUE);
#define CxOff(b)        ActivateCxObj(b,FALSE);
#define BitMask(b)      ( 1L << ((ULONG)b) )

/*
 * Workbench message.
 */
extern struct WBStartup *_WBMsg;

/*
 * Commodity data.
 */
UBYTE                   *CX_PRIORITY      = "PRIORITY";
UBYTE                   *CX_POPWINDOW     = "POPWINDOW";
UBYTE                   *CX_VIEW          = "VIEW";
UBYTE                   *CX_FLUSH         = "FLUSH";
UBYTE                   *CX_QUIT          = "QUIT";

UWORD                    CX_DEF_PRIORITY  = 0;
UBYTE                   *CX_DEF_POPWINDOW = "YES";
UBYTE                   *CX_DEF_VIEW      = "lalt lcommand v";
UBYTE                   *CX_DEF_FLUSH     = "lalt lcommand f";
UBYTE                   *CX_DEF_QUIT      = "lalt lcommand q";

#define                  CX_VERSION         "1.5"
#define                  CX_NAME            "View"
#define                  CX_DESCRIPTION     "Ascii text file viewer."
#define                  CX_COPYRIGHT       "© 1991 Jaba Development"
#define                  CX_TITLE           CX_NAME " " CX_VERSION ", " CX_COPYRIGHT

#define                  CXC_VIEW           1L
#define                  CXC_FLUSH          2L
#define                  CXC_QUIT           3L

UBYTE                   *VW_vers   = "\0$VER: View © 1991 Jaba Development -- v1.5";

struct MsgPort          *VW_cxport = NULL;
struct MsgPort          *VW_idport = NULL;

ULONG                    VW_cxmask = NULL;
ULONG                    VW_idmask = NULL;

UWORD                    VW_dopen  = FALSE;
UWORD                    VW_isopen = FALSE;
UWORD                    VW_fsu    = TRUE;

CxObj                   *VW_broker = NULL;
CxObj                   *VW_view, *VW_flush, *VW_quit;

UBYTE                   *VW_quitstr, *VW_flushstr, *VW_viewstr, *VW_namestr;

struct NewBroker         VW_newbroker = {
    NB_VERSION, CX_NAME, CX_TITLE, CX_DESCRIPTION,
    NBU_NOTIFY | NBU_UNIQUE, COF_SHOW_HIDE, NULL, 0
};

/*
 * Main program data.
 */
struct MsgPort          *VW_cport = NULL;
struct IOStdReq         *VW_creq  = NULL;
struct Window           *VW_wnd   = NULL;
struct Screen           *VW_scr   = NULL;
struct AsciiText        *VW_text  = NULL;
struct FileRequester    *VW_freq  = NULL, *VW_save = NULL;
struct RastPort         *VW_rport;
struct TextFont         *VW_font;
struct Line             *VW_first;
struct Line             *VW_last;

APTR                     VW_wdptr;
struct Process          *VW_proc;

struct RDArgs            VW_iargs = { { 0,0,0 },0,0,0,0,RDAF_NOPROMPT };
struct RDArgs           *VW_fargs = 0L;
struct StringScan        VW_search;
struct TextBlock         VW_blk[10];

ULONG                    VW_args[7] = { 0,0,0,0,0,0,0 };

BOOL                     VW_found = FALSE, VW_printing = FALSE;
BOOL                     VW_err = TRUE;
ULONG                    VW_class, VW_signal, VW_shown;
UWORD                    VW_code, VW_id, VW_qual, VW_ymax;
UWORD                    VW_mode, VW_pmode, VW_maxlin, VW_pmark;
UWORD                    DriPens = ~0;
LONG                     VW_num;

UBYTE                    VW_name[256];
UBYTE                    VW_fbuf[256];
UBYTE                    VW_patt[32] = "#?";

UBYTE                    NullStr     = 0; /* no Enforcer complaints */
UBYTE                   *Template  = "Name,PRIORITY/n,POPWINDOW/k,VIEW/k,FLUSH/k,QUIT/k";
UBYTE                   *GetString = "Type string :";
UBYTE                   *GetLong   = "Type percentage:";
UBYTE                   *Lines[]   = { "ViewSleepy", "Out of memory !",
                                       "Searching...", "ViewPrinting",
                                       "Block %-2.2ld not marked !"
                                     };

UBYTE                   *Dir   = 0L, *SDir = 0L;
UBYTE                   *File  = 0L, *SFile = 0L;

Tag StringTags[] = {
    GTST_String, VW_fbuf, GTST_MaxChars, 256, TAG_DONE };

Tag StringTags1[] = {
    GTST_String, 0L, GTST_MaxChars, 0L, TAG_DONE };

struct StringExtend se = {
    NULL,1,2,1,3,NULL,NULL,NULL,0,0,0,0 };

Tag IntegerTags[] = {
    GTIN_Number, 0, GTIN_MaxChars,3, TAG_DONE };

Tag NewScreenTags[] = {
    SA_Pens, &DriPens, SA_DisplayID, NULL, SA_Overscan, OSCAN_TEXT, TAG_DONE };

Tag NewWindowTags[] = {
    WA_InnerWidth, 200, WA_InnerHeight, 12, TAG_DONE };

Tag NewWindowTags1[] = {
    WA_InnerWidth, 320, WA_InnerHeight, 12, TAG_DONE };

Tag NewWindowTags2[] = {
    WA_RptQueue, 1, TAG_DONE };

Tag RequestTags[] = {
    ASL_LeftEdge, 20, ASL_TopEdge, 15, ASL_Width, 300, ASL_Height, 175,
    ASL_OKText, "Load", ASL_FuncFlags, FILF_PATGAD, TAG_DONE };

Tag RequestTags1[] = {
    ASL_LeftEdge, 20, ASL_TopEdge, 15, ASL_Width, 300, ASL_Height, 175,
    ASL_OKText, "Save", ASL_FuncFlags, FILF_PATGAD | FILF_SAVE, TAG_DONE };

Tag RequestTags2[] = {
    ASL_Window, NULL, ASL_Dir, 0L, ASL_File, 0L,
    ASL_Pattern, &VW_patt[0], ASL_Hail, 0L, TAG_DONE };

Tag ProcessTags[] = {
    NP_Entry, NULL, NP_StackSize, 4096L, NP_Name, "ViewPrinting", TAG_DONE };

struct NewScreen         ns = {
    0,0,640,200,2,-1,-1,HIRES,CUSTOMSCREEN,NULL,NULL,NULL,NULL };

struct NewWindow         nw = {
    0,0,640,200,-1,-1,IDCMP_RAWKEY,
    WFLG_ACTIVATE+WFLG_RMBTRAP+WFLG_SMART_REFRESH+WFLG_BORDERLESS+WFLG_BACKDROP,
    NULL,NULL,NULL,NULL,NULL,0,0,0,0,CUSTOMSCREEN };

struct NewWindow         nws = {
    0,0,200,12,-1,-1,IDCMP_GADGETUP,
    WFLG_RMBTRAP+WFLG_ACTIVATE+WFLG_SMART_REFRESH+WFLG_DRAGBAR,
    NULL,NULL,NULL,NULL,NULL,0,0,0,0,CUSTOMSCREEN };

struct NewWindow         nwe = {
    0,0,320,12,-1,-1,IDCMP_GADGETUP+IDCMP_CLOSEWINDOW,
    WFLG_RMBTRAP+WFLG_CLOSEGADGET+WFLG_ACTIVATE+WFLG_SMART_REFRESH+WFLG_DRAGBAR,
    NULL,NULL,(UBYTE *)"Edit Line",NULL,NULL,0,0,0,0,CUSTOMSCREEN };

struct NewWindow         nwp = {
    0,0,138,11,-1,-1,IDCMP_CLOSEWINDOW,
    WFLG_SMART_REFRESH+WFLG_RMBTRAP+WFLG_DRAGBAR+WFLG_CLOSEGADGET,
    NULL,NULL,(UBYTE *)"Printing...",NULL,NULL,0,0,0,0,CUSTOMSCREEN };

struct TextAttr TOPAZ_80 = {
    (STRPTR)"topaz.font",TOPAZ_EIGHTY,FS_NORMAL,FPF_ROMFONT };

UBYTE   *Header   = "  \033[0;1mView version " CX_VERSION " © 1991 Jaba Development\n"\
                    "      \033[0;33mWritten with DICE C by Jan van den Baard\033[0m\n\n";
UBYTE   *HelpText = " \033[32mSpace\033[0m,\033[32mPg Dn \033[33m \033[0m          : Page down (MORE).\n"\
                    " \033[32mBackspace\033[0m,\033[32mPg Up\033[0m        : Page up (LESS).\n"\
                    " \033[32mReturn\033[0m,\033[32mDn\033[0m,\033[32mNk Dn\033[0m        : Next line.\n"\
                    " \033[32mEnter\033[0m,\033[32mUp\033[0m,\033[32mNk Up\033[0m         : Previous line.\n"\
                    " \033[32m<\033[0m,\033[32mNk Left\033[0m/\033[32m>\033[0m,\033[32mNk Right\033[0m   : First/Last page (TOP/BOTTOM).\n"\
                    " \033[32m/\033[0m,\033[32mF\033[0m                    : Find first (case sensitive).\n"\
                    " \033[32mN\033[0m/\033[32mP\033[0m                    : Find next/previous (case sensitive).\n"\
                    " \033[32m.\033[0m,\033[32mS\033[0m                    : Find first (case insensitive).\n"\
                    " \033[32mCTRL+N\033[0m/\033[32mCTRL+P\033[0m          : Find next/previous (case insensitive).\n"\
                    " \033[32mCTRL+L\033[0m,\033[32mR\033[0m               : Refresh display.\n"\
                    " \033[32m%\033[0m                      : Goto N%.\n"\
                    " \033[32mE\033[0m                      : Edit with ENV:EDITOR.\n"\
                    " \033[32mL\033[0m                      : Load a new file.\n"\
                    " \033[32mJ\033[0m                      : Jump to last found string.\n"\
                    " \033[32mB\033[0m                      : Goto sleep (loose text).\n"\
                    " \033[32mCTRL+B\033[0m                 : Goto sleep (remember text).\n"\
                    " \033[32mLSHIFT+CTRL+D\033[0m/\033[32m+P\033[0m       : Dump page/file to printer.\n"\
                    " \033[32mH\033[0m,\033[32mHELP\033[0m                 : Help page.\n"\
                    " \033[32mQ\033[0m,\033[32mCTRL+C\033[0m,\033[32mESC\033[0m           : Quit view\n\n"\
                    "    \033[31;1mPRESS A KEY FOR MORE";
UBYTE   *HelpText1 = " \033[0;32mFn\033[0m                     : Mark text block #\033[32mn\033[0m.\n"\
                     " \033[32mSHIFT+Fn\033[0m               : Unmark text block #\033[32mn\033[0m.\n"\
                     " \033[32mCTRL+Fn\033[0m                : Jump to text block #\033[32mn\033[0m.\n"\
                     " \033[32mLSHIFT+CTRL+Fn\033[0m         : Print text block #\033[32mn\033[0m.\n"\
                     " \033[32mLALT+Fn\033[0m                : Save text block #\033[32mn\033[0m.\n"\
                     " \033[32mCTRL+S\033[0m                 : Save whole text.\n"\
                     " \033[32mSHIFT+E\033[0m                : Edit a line of text.\n\n"\
                     "    \033[31;1mPRESS A KEY TO CONTINUE";

APTR                         ConsoleDevice = 0L;
extern struct IntuitionBase *IntuitionBase;     /* AUTO INIT */
extern struct GfxBase       *GfxBase;           /* AUTO INIT */
extern struct AslBase       *AslBase;           /* AUTO INIT */
extern struct GadToolsBase  *GadToolsBase;      /* AUTO INIT */
extern struct UtilityBase   *UtilityBase;       /* AUTO INIT */

struct CxBase               *CxBase     = 0L;
struct IconBase             *IconBase   = 0L;
struct NoFragBase           *NoFragBase = 0L;
struct PPBase               *PPBase     = 0L;

#define ESC                  0x1b
#define CSI                  0x9b
#define FF                   0x0c

char    MoveStr[]           = { CSI,0x00,0x00,0x3b,0x00,0x00,0x48,0x00 };
char    ClearStr[]          = { 0x0c,0x00 };
char    ScrUpStr[]          = { CSI,0x53,0x00 };
char    ScrDnStr[]          = { CSI,0x54,0x00 };
char    StdStr[]            = { ESC,0x63,CSI,0x30,0x20,0x70,CSI,0x00,0x38,0x79,0x00 };
char    *ResStr             = "\033[0m";
char    *FFStr              = "\033[7mF\033[0m";

long OpenConsole( void )
{
    if(!(VW_cport = CreateMsgPort()))
        return FALSE;
    if(!(VW_creq = (struct IOStdReq *)CreateIORequest(VW_cport, (long)sizeof(struct IOStdReq))))
        return FALSE;

    VW_creq->io_Data        = (APTR)VW_wnd;
    VW_creq->io_Length      = sizeof(struct Window);

    if(!OpenDevice("console.device",0,(struct IORequest *)VW_creq,0))
        ConsoleDevice       = VW_creq->io_Device;
    else
        return FALSE;

    ConvertKeyTab();
    Inform(StdStr);
    return TRUE;
}

void CloseConsole( void )
{
    if(ConsoleDevice) {
        CloseDevice((struct IORequest *)VW_creq);
        ConsoleDevice = 0L;
    }
    if(VW_creq) {
        DeleteIORequest((struct IORequest *)VW_creq);
        VW_creq = 0L;
    }
    if(VW_cport) {
        DeleteMsgPort(VW_cport);
        VW_cport = 0L;
    }
}

void OpenLibs( void )
{
    if(NOT(NoFragBase = (struct NoFragBase *)OpenLibrary("nofrag.library",NOFRAG_VERSION)))
        Quit( RETURN_FAIL );
    if(NOT(CxBase = (struct CxBase *)OpenLibrary("commodities.library",36L)))
        Quit( RETURN_FAIL );
    if(NOT(IconBase = (struct IconBase *)OpenLibrary("icon.library",36L)))
        Quit( RETURN_FAIL );

    PPBase = (struct PPBase *)OpenLibrary("powerpacker.library",33L);
}

void OpenDisplay( void )
{
    struct Screen *plock;

    if(!(plock = LockPubScreen("Workbench")))
        Quit( RETURN_FAIL );

    ns.Width         = nw.Width  = plock->Width;
    ns.Height        = nw.Height = plock->Height;
    ns.ViewModes     = plock->ViewPort.Modes;
    NewScreenTags[3] = GetVPModeID(&plock->ViewPort);

    UnlockPubScreen(NULL,plock);

    if(!(VW_scr = OpenScreenTagList(&ns,(struct TagItem *)&NewScreenTags[0])))
        Quit( RETURN_FAIL );

    nw.Screen = VW_scr;
    if(!(VW_wnd = OpenWindowTagList(&nw,(struct TagList *)&NewWindowTags2[0])))
        Quit( RETURN_FAIL );

    ShowTitle(VW_scr,FALSE);

    VW_idport             = VW_wnd->UserPort;
    VW_idmask             = BitMask( VW_idport->mp_SigBit );

    VW_proc               = FindTask(0L);
    VW_wdptr              = VW_proc->pr_WindowPtr;
    VW_proc->pr_WindowPtr = (APTR)VW_wnd;
    VW_rport              = VW_wnd->RPort;
    VW_font               = VW_rport->Font;
    VW_maxlin             = (VW_wnd->Height / VW_font->tf_YSize) - 1;
    sprintf((char *)&StdStr[7],"%02.2ldy",VW_font->tf_YSize);
    if(!OpenConsole())
        Quit( RETURN_FAIL );

    VW_isopen = TRUE;

    if(NOT VW_text) {
        if(VW_fsu) {
            if(VW_namestr) {
                if(!ParseName(VW_namestr))
                    LoadFile(TRUE);
                else
                    LoadFile(FALSE);
            } else {
                VW_name[0] = 0;
                Dir  = (char *)&NullStr;
                File = (char *)&NullStr;
                LoadFile(TRUE);
            }
        } else
            LoadFile(TRUE);
    }
    if(VW_text) {
        DisplayText();
        BytesShown();
        InfoLine();
    }
    VW_fsu = FALSE;
}

void CloseDisplay( void )
{
    CloseConsole();
    if(VW_wnd) {
        VW_proc->pr_WindowPtr = VW_wdptr;
        CloseWindow(VW_wnd);
        VW_wnd    = NULL;
        VW_idport = NULL;
        VW_idmask = NULL;
    }
    if(VW_scr) {
        CloseScreen(VW_scr);
        VW_scr = NULL;
    }

    VW_isopen = FALSE;
}

void GetRequest( void )
{
    if(!(VW_freq = AllocAslRequest(ASL_FileRequest,(struct TagItem *)&RequestTags[0])))
        Quit( RETURN_FAIL );
    if(!(VW_save = AllocAslRequest(ASL_FileRequest,(struct TagItem *)&RequestTags1[0])))
        Quit( RETURN_FAIL );
    CLRBLK();
}

void Quit( long code )
{
    CloseDisplay();
    QuitComm();

    if(VW_text)
        FreeAscii(VW_text);
    if(VW_freq)
        FreeAslRequest(VW_freq);
    if(VW_save)
        FreeAslRequest(VW_save);
    if(IconBase)
        CloseLibrary(IconBase);
    if(CxBase)
        CloseLibrary(CxBase);
    if(NoFragBase)
        CloseLibrary(NoFragBase);
    if(VW_fargs)
        FreeArgs(VW_fargs);
    _exit(code);
}

void Inform( char *text )
{
    VW_creq->io_Command = CMD_WRITE;
    VW_creq->io_Data    = (APTR)text;
    VW_creq->io_Length  = (LONG)strlen(text);
    DoIO((struct IORequest *)VW_creq);
}

void Display( struct Line *line )
{
    Inform(ResStr);
    VW_creq->io_Command = CMD_WRITE;
    VW_creq->io_Data    = (APTR)line->Text;
    VW_creq->io_Length  = (LONG)line->Size-1;

    if(line->Text[0] == FF) {
        Inform(FFStr);
        VW_creq->io_Data   = (APTR)&line->Text[1];
        VW_creq->io_Length = (LONG)line->Size-2;
    }
    DoIO((struct IORequest *)VW_creq);
}

void CheckDir( UBYTE *name )
{
    if(name[strlen(name)-1] != ':' && name[strlen(name)-1] != '/' && strlen(name))
            strcat(name,"/");
}

void LoadFile( long request )
{
    UBYTE           *ppdata;
    ULONG            pplen;
    BPTR             ppout;
    BOOL             pptemp = FALSE;
    LONG             pperr;
    UBYTE            lbuf[7], *fname;
    UWORD            lnum = 1;
    LONG             ret;
    struct BuffIO   *file;
    struct Line     *line;

    ErrorLine("View v" CX_VERSION " © 1991 Jaba Development");

    if(request == TRUE) {

        RequestTags2[1]  = VW_wnd;
        RequestTags2[3]  = Dir;
        RequestTags2[5]  = File;
        RequestTags2[9]  = "Please select file to load...";

        ret = AslRequest(VW_freq,(struct TagItem *)&RequestTags2[0]);
        if(ret) {
            Dir  = VW_freq->rf_Dir;
            File = VW_freq->rf_File;
            strcpy(VW_name,Dir);
            strcpy(VW_patt,VW_freq->rf_Pat);
            CheckDir(VW_name);
            strcat(VW_name,File);
        } else {
            InfoLine();
            return;
        }
    }

    if(VW_text) {
        FreeAscii(VW_text);
        VW_text = 0L;
        CLRBLK();
    }

    Inform(ClearStr);
    Inform(StdStr);

    if(PPBase && CheckPP()) {
        ErrorLine("Loading and decrunching file....");
        if((pperr = ppLoadData(VW_name,DECR_POINTER,MEMF_PUBLIC,&ppdata,&pplen,0L)) < 0) {
            switch(pperr) {
                case    PP_OPENERR:
                    ErrorLine("PPLIB: Can't open the file !");
                    break;
                case    PP_READERR:
                    ErrorLine("PPLIB: Read error !");
                    break;
                case    PP_NOMEMORY:
                    ErrorLine("PPLIB: Out of memory !");
                    break;
                case    PP_PASSERR:
                    ErrorLine("PPLIB: Incorrect password !");
                    break;
                case    PP_UNKNOWNPP:
                    ErrorLine("PPLIB: Unknown PowerPacker version !");
                    break;
            }
            return;
        }

        fname = "T:view.pp.tmp.v" CX_VERSION ".decrunched";
        if((ppout = Open(fname,MODE_NEWFILE))) {
            if(Write(ppout,ppdata,pplen) != pplen) {
                ErrorLine("Error writing '.tmp' file !");
                pptemp = FALSE;
            } else
                pptemp = TRUE;
            Close(ppout);
        } else {
            ErrorLine("Can't open '.tmp' file !");
            pptemp = FALSE;
        }
        FreeMem(ppdata,pplen);

        if(!pptemp)
            goto ppCleanUp;
    } else {
        ErrorLine("Loading file....");
        fname = VW_name;
    }


    if((VW_text = AllocAscii(ANSITAB,MAXCOL(VW_wnd,VW_font),ATF_SkipEsc+ATF_TabConvert))) {
        if((file = BOpen(fname,MODE_OLDFILE))) {
            while((line = BGetS(file,VW_text)))
                AddTail((struct List *)VW_text,(struct Node *)line);

            switch(BIoErr(file)) {
                case ASE_READ:
                    ErrorLine("READ ERROR !");
                    goto CleanExit;
                case ASE_NOMEM:
                    ErrorLine(Lines[1]);
                    goto CleanExit;
            }
            BClose(file);
            VW_first = VW_text->First;
            VW_found = FALSE;
            DisplayText();
            BytesShown();
            ClearMsg(VW_wnd->UserPort);
            InfoLine();
            goto ppCleanUp;
        } else {
            ErrorLine("Could not open the file !");
            FreeAscii(VW_text);
            VW_text = 0L;
            goto ppCleanUp;
        }
    } else {
        ErrorLine(Lines[1]);
        goto ppCleanUp;
    }
CleanExit:
    FreeAscii(VW_text);
    VW_text = 0L;
    BClose(file);
    ClearMsg(VW_wnd->UserPort);
ppCleanUp:
    if(pptemp)
        DeleteFile(fname);
}

void DisplayText( void )
{
    UWORD   y=1,i=0;

    if(!VW_text)    return;

    for(VW_last = VW_first; i < VW_maxlin; i++, VW_last = VW_last->Next, y++) {
        if(VW_last == VW_text->Last->Next)  break;
        MoveTo(1,y);
        Display(VW_last);
        if(VW_found && VW_last == VW_search.Line) PrintFound(y);
    }
    VW_ymax = y-1;
}

void MoveTo(UBYTE c, UBYTE r)
{
    sprintf((char *)&MoveStr[1],"%02ld;%02ldH",r,c);
    Inform(MoveStr);
}

void LineDown( void )
{
    if(!VW_text)    return;
    if(VW_last == VW_text->Last->Next) return;

    VW_first = VW_first->Next;
    Inform(ScrUpStr);
    MoveTo(1,VW_ymax);
    Display(VW_last);

    VW_shown += VW_last->Size;
    if(VW_found && VW_last == VW_search.Line) PrintFound(VW_ymax);

    VW_last = VW_last->Next;
}

void LineUp( void )
{
    if(!VW_text)    return;
    if(VW_first == VW_text->First) return;

    VW_last   = VW_last->Prev;
    VW_shown -= VW_last->Size;
    VW_first  = VW_first->Prev;
    Inform(ScrDnStr);
    MoveTo(1,1);
    Display(VW_first);
    if(VW_found && VW_first == VW_search.Line) PrintFound(1);
}

void Top( void )
{
    if(!VW_text) return;
    if(VW_first == VW_text->First) return;

    VW_first = VW_text->First;
    Inform(ClearStr);
    DisplayText();
    BytesShown();
}

void Bottom( void )
{
    UWORD   i;

    if(!VW_text)    return;
    if(VW_last == VW_text->Last->Next) return;

    VW_last = VW_first = VW_text->Last;

    for(i = 1; i < VW_maxlin; i++)
        VW_first = VW_first->Prev;

    VW_shown = VW_text->NumBytes;
    Inform(ClearStr);
    DisplayText();
}

void PageDown( void )
{
    UWORD   i;

    if(!VW_text) return;
    if(VW_last == VW_text->Last->Next) return;

    for(i = 1; i < VW_maxlin; i++) {
        VW_first  = VW_first->Next;
        VW_shown += VW_last->Size;
        if((VW_last = VW_last->Next) == VW_text->Last->Next) break;
    }

    Inform(ClearStr);
    DisplayText();
}

void PageUp( void )
{
    UWORD   i;

    if(!VW_text) return;
    if(VW_first == VW_text->First) return;

    for(i = 1; i < VW_maxlin; i++) {
        VW_last   = VW_last->Prev;
        VW_shown -= VW_last->Size;
        if((VW_first = VW_first->Prev) == VW_text->First) break;
    }
    Inform(ClearStr);
    DisplayText();
}

void Percentage( void )
{
    ULONG   perc;
    char    pcbuf[5];

    if(!VW_text)    return;
    perc = (ULONG)(VW_shown * 100 / VW_text->NumBytes);
    if(perc == 100 && (VW_last != VW_text->Last->Next)) perc = 99;
    VW_num = perc;
    sprintf(pcbuf,"%3ld%%",perc);
    SetAPen(VW_rport,3);
    SetBPen(VW_rport,2);
    SetDrMd(VW_rport,JAM2);
    Move(VW_rport,544,VW_font->tf_Baseline);
    Text(VW_rport,pcbuf,strlen(pcbuf));
    SetAPen(VW_rport,1);
    Move(VW_rport,584,VW_font->tf_Baseline);
    Text(VW_rport,"Shown.",6);
}

void BytesShown( void )
{
    struct Line *line;

    VW_shown = 0L;

    for(line = VW_text->First; line != VW_last; line = line->Next)
        VW_shown += line->Size;
}

void InfoLine( void )
{
    UBYTE   ibuf[100];

    CLRLIN();

    VW_err = FALSE;

    SetAPen(VW_rport,1);
    SetDrMd(VW_rport,JAM1);

    if(VW_text) {
        sprintf(ibuf,"File : %-31.31ls %-6.6ld Lines, %-6.6ld Bytes.",VW_name,VW_text->NumLines-VW_text->NumSplit,VW_text->NumBytes);
    } else
        strcpy(ibuf,"No text in memory (press 'l' to load a file)");

    Move(VW_rport,1,VW_font->tf_Baseline);
    Text(VW_rport,ibuf,strlen(ibuf));
}

void ErrorLine( UBYTE *text )
{
    CLRLIN();
    VW_err = TRUE;
    SetAPen(VW_rport,1);
    SetDrMd(VW_rport,JAM1);
    Move(VW_rport,1,VW_font->tf_Baseline);
    Text(VW_rport,text,strlen(text));
}

void WaitKey( void )
{
    while(1) {
        WaitPort(VW_wnd->UserPort);
        while(HandleMsg(VW_wnd->UserPort));
        if(((VW_code & IECODE_UP_PREFIX) != IECODE_UP_PREFIX) &&
           (!(VW_qual & IEQUALIFIER_REPEAT)))
            break;
    }
    ClearMsg(VW_wnd->UserPort);
}

void Help( void )
{
    Move(VW_rport,0,0);
    SetAPen(VW_rport,0);
    SetDrMd(VW_rport,JAM1);
    ClearScreen(VW_rport);

    MoveTo(1,1);
    Inform(Header);
    Inform(HelpText);

    WaitKey();

    Move(VW_rport,0,0);
    SetAPen(VW_rport,0);
    SetDrMd(VW_rport,JAM1);
    ClearScreen(VW_rport);

    MoveTo(1,1);
    Inform(Header);
    Inform(HelpText1);

    WaitKey();

    Move(VW_rport,0,0);
    SetAPen(VW_rport,0);
    SetDrMd(VW_rport,JAM1);
    ClearScreen(VW_rport);
    DisplayText();
    InfoLine();
}

long CountEsc(struct Line *line, long off)
{
    UWORD   i;
    LONG    c = 0L;
    char   *ptr = line->Text, chr;

    for(i = 0;i <= off; i++) {
        if((*ptr == ESC) || (*ptr == CSI)) {
            while(1) {
               c++;
               i++;
               chr = (*ptr++) - ' ';
               if((chr >= '?' && chr <= 'Z') || !chr) break;
            }
        }
        else ptr++;
    }
    return(c);
}

void DoFound( void )
{
    struct Line *line;
    USHORT       i,y=0,yy;

    VW_last = VW_search.Line;

    for(i = 0; i < VW_maxlin; i++)
        if((VW_last = VW_last->Next) == VW_text->Last->Next) break;

    VW_first = VW_last;

    for(yy = VW_ymax, i = VW_maxlin; i >= 1; i--, yy--) {
        if((VW_first = VW_first->Prev) == VW_text->First) break;
        if(VW_first == VW_search.Line) y = yy;
    }

    VW_shown = 0L;

    for(line = VW_text->First; line != VW_last; line = line->Next)
        VW_shown += line->Size;

    Inform(ClearStr);
    DisplayText();
}

void PrintFound( UWORD y )
{
    char wrd[256];

    setmem(&wrd[0],256,0);

    Inform("\033[32;43m");
    strncpy(wrd,(char *)&VW_search.Line->Text[VW_search.TextOffset],VW_search.StringSize);
    MoveTo(VW_search.TextOffset - CountEsc(VW_search.Line,VW_search.TextOffset)+1,y);
    Inform(wrd);
    Inform(ResStr);
}

void GetSomething( ULONG kind )
{
    struct Gadget    *g = 0L, *glist = 0L;
    struct Window    *w = 0L;
    struct Line      *line;
    struct NewGadget  ng;
    APTR              vi = 0L;
    ULONG             sizex = 0L, sizen = 0L, i;

    if(!VW_text) return;

    setmem(&ng,sizeof(struct NewGadget),0);

    nws.Screen   = VW_scr;
    nws.LeftEdge = (VW_wnd->Width >> 1) - 106;
    nws.TopEdge  = (VW_wnd->Height >> 1) - 12;
    if(kind == STRING_KIND)
        nws.Title    = GetString;
    else
        nws.Title    = GetLong;

    if((w = OpenWindowTagList(&nws,(struct TagItem *)&NewWindowTags[0]))) {
        if((vi = GetVisualInfoA(VW_scr,(struct TagItem *)&StringTags[4]))) {
            if((g = CreateContext(&glist))) {

                ng.ng_LeftEdge   = w->BorderLeft;
                ng.ng_TopEdge    = w->BorderTop;
                ng.ng_Width      = 200;
                ng.ng_Height     = 12;
                ng.ng_TextAttr   = &TOPAZ_80;
                ng.ng_VisualInfo = vi;

                if(kind == STRING_KIND)
                    g = CreateGadgetA(STRING_KIND,g,&ng,(struct TagItem *)&StringTags[0]);
                else {
                    IntegerTags[1] = VW_num;
                    g = CreateGadgetA(INTEGER_KIND,g,&ng,(struct TagItem *)&IntegerTags[0]);
                }
                if(g) {
                    g->Activation |= GACT_STRINGCENTER;
                    g->Activation |= GACT_STRINGEXTEND;
                    se.InitialModes = NULL;
                    ((struct StringInfo *)g->SpecialInfo)->Extension = &se;
                    AddGList(w,glist,-1L,-1L,NULL);
                    RefreshGList(glist,w,NULL,-1);
                    GT_RefreshWindow(w,NULL);
                    ActivateGadget(g,w,NULL);

                    while(1) {
                        WaitPort(w->UserPort);
                        while(HandleMsg(w->UserPort));
                        if(VW_class == IDCMP_GADGETUP) {
                            if(kind == STRING_KIND) {
                                strcpy(VW_fbuf,((struct StringInfo *)g->SpecialInfo)->Buffer);
                                CloseWindow(w);
                                w = 0L;
                                ErrorLine(Lines[2]);
                                if(FindFrom(VW_text,VW_fbuf,&VW_search,VW_first,VW_mode)) {
                                    VW_found = TRUE;
                                    DoFound();
                                    InfoLine();
                                    goto CleanExit;
                                } else {
                                    VW_found = FALSE;
                                    DisplayBeep(VW_scr);
                                    InfoLine();
                                    goto CleanExit;
                                }
                            } else {
                                CloseWindow(w);
                                w = 0L;
                                VW_num = ((struct StringInfo *)g->SpecialInfo)->LongInt;
                                if(VW_num > 0 && VW_num < 100) {

                                    sizen = VW_num * VW_text->NumBytes / 100;

                                    for(line = VW_text->First; line->Next; line = line->Next) {
                                        sizex += line->Size;
                                        if(sizex > sizen) break;
                                    }

                                    VW_first = line;

                                    for(i = 1; i < VW_maxlin; i++ )
                                        if((VW_first = VW_first->Prev) == VW_text->First) break;

                                    VW_last = VW_first;

                                    for(i = 1; i < VW_maxlin; i++)
                                        if((VW_last = VW_last->Next) == VW_text->Last->Next) break;

                                    VW_shown = 0L;
                                    for(line = VW_text->First; line != VW_last->Next; line = line->Next)
                                        VW_shown += line->Size;

                                    Inform(ClearStr);
                                    DisplayText();
                                    goto CleanExit;
                                } else if(VW_num == 100) {
                                    Bottom();
                                    goto CleanExit;
                                } else if(!VW_num) {
                                    Top();
                                    goto CleanExit;
                                } else {
                                    DisplayText();
                                    DisplayBeep(VW_scr);
                                    goto CleanExit;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
CleanExit:
    if(w)           CloseWindow(w);
    if(vi)          FreeVisualInfo(vi);
    if(glist)       FreeGadgets(glist);
    ClearMsg(VW_wnd->UserPort);
}

struct Line *MakeNewLine( UBYTE *text )
{
    struct Line *line = NULL, *rep;
    UBYTE       *txt = NULL;
    UWORD        len;

    rep = VW_first;
    len = strlen(text)+1;

    if((line = (struct Line *)AllocItem(VW_text->MemoryUsed,(ULONG)sizeof(struct Line),MEMF_PUBLIC))) {
        if(txt = (UBYTE *)AllocItem(VW_text->MemoryUsed,(ULONG)len,MEMF_PUBLIC)) {

            strcpy(txt,text);
            if(txt[len-1] != 0x0A)
                txt[len-1] = 0x0A;

            line->Flags = rep->Flags;
            line->Size  = len-1;
            line->Text  = txt;

            Insert((void *)VW_text,(void *)line,(void *)rep);

            Remove(rep);
            FreeItem(VW_text->MemoryUsed,rep->Text,rep->Size);
            FreeItem(VW_text->MemoryUsed,rep,(ULONG)sizeof(struct Line));

            VW_first = line;
            Inform(ClearStr);
            DisplayText();
            return;
        }
    }
    ErrorLine(Lines[1]);
    if(txt)  FreeItem(VW_text->MemoryUsed,txt,len);
    if(line) FreeItem(VW_text->MemoryUsed,line,(ULONG)sizeof(struct Line));
}

void EditLine( void )
{
    struct Gadget    *g = 0L, *glist = 0L;
    struct Window    *w = 0L;
    struct NewGadget  ng;
    APTR              vi = 0L;
    UBYTE             TextLine[257];

    if(!VW_text) return;

    setmem(&ng,sizeof(struct NewGadget),0);
    setmem(&TextLine[0],257,0);

    nwe.Screen   = VW_scr;
    nwe.LeftEdge = (VW_wnd->Width >> 1) - 166;
    nwe.TopEdge  = (VW_wnd->Height >> 1) - 12;

    if((w = OpenWindowTagList(&nwe,(struct TagItem *)&NewWindowTags1[0]))) {
        if((vi = GetVisualInfoA(VW_scr,(struct TagItem *)&StringTags[4]))) {
            if((g = CreateContext(&glist))) {

                ng.ng_LeftEdge   = w->BorderLeft;
                ng.ng_TopEdge    = w->BorderTop;
                ng.ng_Width      = 320;
                ng.ng_Height     = 12;
                ng.ng_TextAttr   = &TOPAZ_80;
                ng.ng_VisualInfo = vi;

                strncpy(TextLine,VW_first->Text,VW_first->Size);

                StringTags1[1] = TextLine;
                StringTags1[3] = MAXCOL(VW_wnd,VW_font);

                g = CreateGadgetA(STRING_KIND,g,&ng,(struct TagItem *)&StringTags1[0]);

                g->Activation  |= GACT_STRINGEXTEND;
                se.InitialModes = SGM_NOFILTER;
                ((struct StringInfo *)g->SpecialInfo)->Extension = &se;

                if(g) {
                    g->Activation |= GACT_STRINGCENTER;
                    AddGList(w,glist,-1L,-1L,NULL);
                    RefreshGList(glist,w,NULL,-1);
                    GT_RefreshWindow(w,NULL);
                    ActivateGadget(g,w,NULL);

                    while(1) {
                        WaitPort(w->UserPort);
                        while(HandleMsg(w->UserPort));
                        if(VW_class == IDCMP_GADGETUP) {
                            MakeNewLine((UBYTE *)((struct StringInfo *)g->SpecialInfo)->Buffer);
                            break;
                        } else
                            break;
                    }
                }
            }
        }
    }
CleanExit:
    if(w)           CloseWindow(w);
    if(vi)          FreeVisualInfo(vi);
    if(glist)       FreeGadgets(glist);
    ClearMsg(VW_wnd->UserPort);
}

void FindN( void )
{
    if(!VW_text) return;

    if(VW_found) {
        ErrorLine(Lines[2]);
        if(NextOccurrence(&VW_search,VW_mode)) {
            DoFound();
            InfoLine();
            return;
        }
    }
    InfoLine();
    DisplayBeep(VW_scr);
}

void FindP( void )
{
    if(!VW_text) return;

    if(VW_found) {
        ErrorLine(Lines[2]);
        if(PreviousOccurrence(&VW_search,VW_mode)) {
            DoFound();
            InfoLine();
            return;
        }
    }
    InfoLine();
    DisplayBeep(VW_scr);
}

/*
 * Run the editor described in the environment variable
 * 'EDITOR'. The editor may NOT be crunched!
 */
void EditFile( void )
{
    struct  Segment *resseg;
    BPTR    segment;
    WORD    elen, rc;
    UBYTE   ebuf[256]; /* should be enough to hold the editor path & name */

    if(!VW_text)    return;

    if((elen = GetVar("EDITOR",ebuf,256,NULL)) > 0) {
        Forbid();
        resseg = FindSegment(ebuf,0,0);
        Permit();
        if(resseg) { /* Found it on the resident list */
            ScreenToBack(VW_scr);
            rc = RunCommand(resseg->seg_Seg,8192L,VW_name,strlen(VW_name));
            goto RunExit;
        } else if((segment = LoadSeg(ebuf))) { /* loaded it from disk */
            ScreenToBack(VW_scr);
            rc = RunCommand(segment,8192L,VW_name,strlen(VW_name));
            UnLoadSeg(segment);
            goto RunExit;
        } else {
            ErrorLine("Could not run the editor !");
            goto CleanExit;
        }
    } else {
        ErrorLine("ENV:EDITOR variable not set (Use SetEnv) !");
        goto CleanExit;
    }

RunExit:
    sprintf(ebuf,"Editor return code : %ld",rc);
    ErrorLine(ebuf);
CleanExit:
    ScreenToFront(VW_scr);
    return;
}

long CheckBlock( UWORD mark )
{
    UBYTE   errl[31];

    if(!VW_blk[mark].TopLine || !VW_blk[mark].BottomLine) {
        sprintf(errl,Lines[4],mark+1);
        ErrorLine(errl);
        return(FALSE);
    }
    return(TRUE);
}

void PrintFile( void )
{
    if(!VW_text)    return;

    if(VW_pmode == PRT_BLOCK) {
        if(!CheckBlock(VW_pmark))
            return;
    }

    ProcessTags[1] = PrintProc;

    if(!CreateNewProc((struct TagItem *)&ProcessTags[0]))
        ErrorLine("Can't start printing process !");
    else {
        while(!FindTask(Lines[3]));
        VW_printing = TRUE;
    }
}

__geta4 void PrintProc( void )
{
    struct BuffIO       *pfile = 0L;
    struct Window       *pwin = 0L;
    struct IntuiMessage *pmsg;
    struct Line         *l, *t;
    ULONG                class;

    if(!VW_text) return;

    if((pfile = BOpen("PRT:",MODE_NEWFILE))) {
        nwp.Screen = VW_scr;
        if((pwin = OpenWindow(&nwp))) {
            if(VW_pmode == PRT_PAGE) {
                l = VW_first;
                t = VW_last;
            } else if(VW_pmode == PRT_FILE) {
                l = VW_text->First;
                t = VW_text->Last->Next;
            } else {
                l = VW_blk[VW_pmark].TopLine;
                t = VW_blk[VW_pmark].BottomLine;
            }

            for( ; l != t; l = l->Next) {
                if((pmsg = GT_GetIMsg(pwin->UserPort))) {
                    class = pmsg->Class;
                    GT_ReplyIMsg(pmsg);
                }
                if(class == IDCMP_CLOSEWINDOW)
                    goto CleanExit;

                BPutS(pfile,l);

                if(BIoErr(pfile) != ASE_OK) {
                    ErrorLine("Print error !");
                    goto CleanExit;
                }
            }
        }
    } else
        ErrorLine("Printer trouble !");
CleanExit:
    if(pwin)        CloseWindow(pwin);
    if(pfile)       BClose(pfile);
}

long IsItADir( void )
{
    struct FileInfoBlock    *fib;
    BPTR                     lock;
    long                     ret = -1L;

    if((fib = AllocMem((ULONG)sizeof(struct FileInfoBlock),MEMF_PUBLIC))) {
        if((lock = Lock((char *)&VW_name[0],ACCESS_READ))) {
            Examine(lock,fib);
            ret = fib->fib_DirEntryType;
            UnLock(lock);
        }
        FreeMem(fib,(ULONG)sizeof(struct FileInfoBlock));
    }
    return(ret);
}

long ParseName( char *arg )
{
    char *str;

    if(arg) {
        if((str = (char *)strrchr(arg,'/')) || (str = (char *)strrchr(arg,':'))) {
            if(IsItADir() < 0) {
                str++;
                File = &VW_name[str-arg];
                *str = 0;
                Dir = arg;
                if(strlen(File))
                    return TRUE;
                else
                    return FALSE;
            } else {
                Dir = &VW_name[0];
                File = &NullStr;
                return FALSE;
            }
        }
        if(arg[0]) {
            if(IsItADir() > 0) {
                Dir = arg;
                File = &NullStr;
                return FALSE;
            } else {
                File = arg;
                Dir = &NullStr;
                return TRUE;
            }
        }
    }
    Dir = File = &NullStr;
    return FALSE;
}

long CheckPP( void )
{
    BPTR    file;
    ULONG   ident;

    if(!(file = Open(VW_name,MODE_OLDFILE))) {
        strcat(VW_name,".pp");
        if(!(file = Open(VW_name,MODE_OLDFILE))) {
            ErrorLine("Could not open the file");
            return FALSE;
        }
    }
    Read(file,&ident,4L);
    Close(file);
    if(ident == 'PP20' || ident == 'PX20') return TRUE;
    return FALSE;
}

void myMain( BOOL cli )
{
    struct WBArg *wba;

    OpenLibs();
    GetRequest();

    if(NOT cli) {
        if(_WBMsg->sm_ArgList->wa_Lock)
            CurrentDir(_WBMsg->sm_ArgList->wa_Lock);
    }

    SetupComm();
    MainLoop();
    return;
}

void SetMark( UWORD mark )
{
    struct Line     *line, *lt;
    UBYTE            errl[31];

    if(!VW_text)    return;

    if(!VW_blk[mark].TopLine) {
        VW_blk[mark].TopLine = VW_first;
        return;
    } else if(!VW_blk[mark].BottomLine) {
        VW_blk[mark].BottomLine = VW_last;

        for(line = VW_text->First; line->Next; line = line->Next) {
            if(line == VW_blk[mark].TopLine) break;
            else if(line == VW_blk[mark].BottomLine) {
                lt = VW_blk[mark].TopLine;
                VW_blk[mark].TopLine    = line->Prev;
                VW_blk[mark].BottomLine = lt->Next;
                break;
            }
        }
        sprintf(errl,"Block %-2.2ld marked !",mark+1);
        ErrorLine(errl);
        return;
    } else {
        sprintf(errl,"Block %-2.2ld already marked !",mark+1);
        ErrorLine(errl);
        return;
    }
}

void UnSetMark( UWORD mark )
{
    UBYTE   errl[31];

    if(!VW_text)    return;

    VW_blk[mark].TopLine = VW_blk[mark].BottomLine = NULL;

    sprintf(errl,"Block %-2.2ld unmarked !",mark+1);
    ErrorLine(errl);
}

void JumpMark( UWORD mark )
{
    struct Line *line;

    if(!VW_text)    return;

    if(!CheckBlock(mark))
        return;

    VW_first = VW_blk[mark].TopLine;
    Inform(ClearStr);
    DisplayText();
    VW_shown = 0L;

    for(line=VW_text->First; line != VW_last; line = line->Next)
        VW_shown += line->Size;

    Percentage();
}

void SaveBlock( WORD mark )
{
    struct BuffIO       *ofile;
    struct Line         *f, *t;
    ULONG                ret;
    UBYTE                oname[256];

    if(mark >= 0) {
        if(!CheckBlock(mark))
            return;
    } else {
        if(NOT VW_text)
            return;
    }

    RequestTags2[1]  = VW_wnd;
    RequestTags2[3]  = SDir;
    RequestTags2[5]  = SFile;
    if(mark >= 0)
        RequestTags2[9]  = "Save text block as...";
    else
        RequestTags2[9]  = "Save text as...";

    ret = AslRequest(VW_save,(struct TagItem *)&RequestTags2[0]);
    if(ret) {
        SDir  = VW_save->rf_Dir;
        SFile = VW_save->rf_File;
        strcpy(oname,SDir);
        strcpy(VW_patt,VW_save->rf_Pat);
        CheckDir(oname);
        strcat(oname,SFile);
    } else {
        InfoLine();
        return;
    }

    if((ofile = BOpen((char *)&oname[0],MODE_NEWFILE))) {
        ErrorLine("Writing...");
        if(mark >= 0) {
            f = VW_blk[mark].TopLine;
            t = VW_blk[mark].BottomLine;
        } else {
            f = VW_text->First;
            t = VW_text->Last->Next;
        }

        for( ; f != t; f = f->Next )
            BPutS(ofile,f);

        if(BClose(ofile) != ASE_OK)
            ErrorLine("Write Error !");
    } else
        ErrorLine("Can't open write file !");
    InfoLine();
}

void SetupComm( void )
{
    struct WBArg *wba;
    char         *popwindow, **tooltypes;
    long          priority;

    if(_WBMsg) {
        tooltypes = ArgArrayInit( 0L, _WBMsg );

        priority    = ArgInt( tooltypes, CX_PRIORITY, CX_DEF_PRIORITY );
        popwindow   = ArgString( tooltypes, CX_POPWINDOW, CX_DEF_POPWINDOW );
        VW_viewstr  = ArgString( tooltypes, CX_VIEW, CX_DEF_VIEW );
        VW_flushstr = ArgString( tooltypes, CX_FLUSH, CX_DEF_FLUSH );
        VW_quitstr  = ArgString( tooltypes, CX_QUIT, CX_DEF_QUIT );

        wba = (struct WBArg *)_WBMsg->sm_ArgList;
        if(_WBMsg->sm_NumArgs > 1) {
            wba++;
            CurrentDir(wba->wa_Lock);
            strcpy(VW_name,(char *)wba->wa_Name);
            VW_namestr = (char *)wba->wa_Name;
        }
    } else {
        strcpy(VW_name,(char *)VW_args[0]);

        VW_namestr  = (char *)VW_args[0];

        if(VW_args[1])  priority    = VW_args[1];
        else            priority    = CX_DEF_PRIORITY;
        if(VW_args[2])  popwindow   = (char *)VW_args[2];
        else            popwindow   = CX_DEF_POPWINDOW;
        if(VW_args[3])  VW_viewstr  = (char *)VW_args[3];
        else            VW_viewstr  = CX_DEF_VIEW;
        if(VW_args[4])  VW_flushstr = (char *)VW_args[4];
        else            VW_flushstr = CX_DEF_FLUSH;
        if(VW_args[5])  VW_quitstr  = (char *)VW_args[5];
        else            VW_quitstr  = CX_DEF_QUIT;
    }


    if(NOT Stricmp( popwindow, CX_DEF_POPWINDOW )) VW_dopen = TRUE;
    else                                           VW_dopen = FALSE;

    if(NOT( VW_cxport = CreateMsgPort()))
        Quit( RETURN_FAIL );

    VW_newbroker.nb_Pri  = priority;
    VW_newbroker.nb_Port = VW_cxport;

    VW_cxmask            = BitMask( VW_cxport->mp_SigBit );

    if(NOT( VW_broker = CxBroker( &VW_newbroker, NULL )))
        Quit( RETURN_FAIL );

    if(NOT( VW_quit = HotKey( VW_quitstr, VW_cxport, CXC_QUIT )))
        Quit( RETURN_FAIL );
    AttachCxObj( VW_broker, VW_quit );

    if(NOT( VW_flush = HotKey( VW_flushstr, VW_cxport, CXC_FLUSH )))
        Quit( RETURN_FAIL );
    AttachCxObj( VW_broker, VW_flush );

    if(NOT( VW_view = HotKey( VW_viewstr, VW_cxport, CXC_VIEW )))
        Quit( RETURN_FAIL );
    AttachCxObj( VW_broker, VW_view );

    if(CxObjError( VW_quit ) || CxObjError( VW_flush ) || CxObjError( VW_view ))
        Quit( RETURN_FAIL );

    if(_WBMsg)
        ArgArrayDone();

    CxOn( VW_broker );
}

void QuitComm( void )
{
    struct Message  *tmp;

    if(VW_broker)
        DeleteCxObjAll( VW_broker );
    if(VW_cxport) {
        ClearMsg( VW_cxport );
        DeleteMsgPort( VW_cxport );
    }
}

void MainLoop( void )
{
    struct Message      *msg;
    struct IntuiMessage *imsg;
    ULONG                sig, type, id, class;
    BOOL                 running = TRUE;

    if(VW_dopen)    OpenDisplay();

    do {
        if(VW_isopen)   Percentage();

        sig = Wait( SIGBREAKF_CTRL_C | VW_cxmask | VW_idmask );

        if(( sig & SIGBREAKF_CTRL_C ) == SIGBREAKF_CTRL_C ) {
            running = FALSE;
        } else if(( sig & VW_cxmask ) == VW_cxmask ) {

            while (( msg = (struct Message *)GetMsg( VW_cxport ))) {

                id   = CxMsgID((CxMsg *)msg);
                type = CxMsgType((CxMsg *)msg);
                ReplyMsg(msg);

                switch( type ) {

                    case    CXM_IEVENT:

                        switch( id ) {

                            case    CXC_VIEW:
                                    if(NOT VW_isopen)
                                        OpenDisplay();
                                    else
                                        ScreenToFront( VW_scr );
                                    break;

                            case    CXC_FLUSH:
                                    if(NOT VW_isopen) {
                                        FreeAscii(VW_text);
                                        VW_text = NULL;
                                    }
                                    break;

                            case    CXC_QUIT:
                                    if(NOT VW_isopen)
                                        running = FALSE;
                                    break;
                        }
                        break;

                    case    CXM_COMMAND:
                        switch( id ) {

                            case    CXCMD_KILL:
                                running = FALSE;
                                break;

                            case    CXCMD_DISABLE:
                                CxOff( VW_broker );
                                break;

                            case    CXCMD_ENABLE:
                                CxOn( VW_broker );
                                break;

                            case    CXCMD_UNIQUE:
                            case    CXCMD_APPEAR:
                                if(NOT VW_isopen)
                                    OpenDisplay();
                                else
                                    ScreenToFront( VW_scr );
                                break;

                            case    CXCMD_DISAPPEAR:
                                if(VW_isopen)
                                    CloseDisplay();
                                break;
                        }
                        break;
                }
            }
        } else if(VW_isopen) {
            if(( sig & VW_idmask ) == VW_idmask) {

                while(HandleMsg(VW_wnd->UserPort)) {
                    Percentage();
                    Forbid();
                    if(!FindTask(Lines[3])) VW_printing = FALSE;
                    Permit();

                    if(VW_class == IDCMP_RAWKEY)
                            HandleKeyboard( VW_code, VW_qual );
                }
            }
        }
    } while( running == TRUE );

    if(VW_isopen)
        CloseDisplay();
    CxOff( VW_broker );
    Quit(NULL);
}

extern struct Library *SysBase;

/*
 * I don't use the stdio routines from the c.lib and
 * I use "ReadArgs()" to parse the arguments so I can
 * safely use the "_main" entry point. This saves a
 * hell of a lot of bytes in the executable.
 */
void _main( void )
{
    struct Process              *proc = FindTask(NULL);

    if(SysBase->lib_Version < 36) /* sanity check */
        _exit(RETURN_FAIL);

    if(proc->pr_CLI) {
        if((VW_fargs = ReadArgs(Template,&VW_args[0],&VW_iargs)))
            myMain(TRUE);
            return;
    } else {
        myMain(FALSE);
        return;
    }

    _waitwbmsg(); /* to get the workbench message, dummy! never called! */
    atoi("");
}
