/*-- 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.0
*   Translator      :   DICE v2.6
*
*   REVISION HISTORY
*
*   Date          Version         Comment
*   ---------     -------         ------------------------------------------
*   21-Apr-91     1.0             View main program. OS 2 ONLY!
*
*-- REV_END --*/

#include "view.h"

long OpenConsole( void );
void CloseConsole( void );
void GetRes( void );
__regargs void Quit( long );
__regargs void Inform( char * );
__regargs void Display( struct Line * );
__regargs void LoadFile( long );
void DisplayText( void );
__regargs 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 );
__regargs void ErrorLine( UBYTE * );
void WaitKey( void );
void Help( void );
__regargs long CountEsc( struct Line *, long );
void DoFound( void );
__regargs void PrintFound( UWORD );
__regargs void GetSomething( ULONG );
void FindN( void );
void FindP( void );
void EditFile( void );
void PrintFile( void );
void PrintProc( void );
long CheckPP( void );
__regargs long ParseName( char * );
__regargs void SetMark( UWORD );
__regargs void UnSetMark( UWORD );
__regargs void JumpMark( UWORD );
__regargs void myMain( BOOL );

extern void _waitwbmsg( void );

extern __regargs void exit( int );
extern __regargs int  _parseargs1( char *, int );
extern __regargs void _parseargs2( char *, char **, int );

extern void ConvertKeyTab( void );
extern __regargs void HandleKeyboard( UWORD, UWORD );
extern __regargs void SteadyRepeat( struct MsgPort * );
extern __regargs long HandleMsg( struct MsgPort * );
extern __regargs void ClearMsg( struct MsgPort * );
extern __stkargs struct InputEvent *HandlerStub( struct InputEvent *, struct HandlerMuck * );

#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);

extern struct WBStartup *_WBMsg;

struct MsgPort          *VW_cport = 0L;
struct IOStdReq         *VW_creq  = 0L;
struct Window           *VW_wnd   = 0L;
struct Screen           *VW_scr   = 0L;
struct AsciiText        *VW_text  = 0L;
struct FileRequester    *VW_freq  = 0L;
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 HandlerMuck       VW_data;
struct Interrupt         VW_int;
struct TextBlock         VW_blk[10];

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

BOOL                     VW_found = FALSE, VW_printing = FALSE, 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;
LONG                     VW_num;

UBYTE                    VW_name[256];
UBYTE                    VW_fbuf[256];

UBYTE                    *Template  = "Name";
UBYTE                    *GetString = "Type string :";
UBYTE                    *GetLong   = "Type percentage:";
UBYTE                    *Lines[]   = { "ViewSleepy",
                                        "Out of memory !",
                                        "Searching...",
                                        "ViewPrinting",
                                        "Block %-2.2ld not marked !"   };
UBYTE                    *Dir = 0L;
UBYTE                    *File = 0L;

UWORD   DriPens[NUMDRIPENS+1] = {
    0,1,1,2,1,3,1,0,1,~0
};

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

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

Tag NewScreenTags[] = {
    SA_Pens,&DriPens[0],
    TAG_DONE
};

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

Tag RequestTags[] = {
    ASL_Hail,"Please select file to load",
    ASL_LeftEdge,20,
    ASL_TopEdge,15,
    ASL_Width,300,
    ASL_Height,175,
    ASL_OKText,"Load",
    TAG_DONE
};

Tag RequestTags2[] = {
    ASL_Window,NULL,
    ASL_Dir,0L,
    ASL_File,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         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 1.0 © 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\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 */
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 = CreatePort("ViewConsole",0L)))
        return FALSE;
    if(!(VW_creq = CreateStdIO(VW_cport)))
        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;

    Inform(StdStr);
    return TRUE;
}

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

void GetRes( void )
{
    struct Screen *plock;

    if(!(NoFragBase = (struct NoFragBase *)
      OpenLibrary("nofrag.library",NOFRAG_VERSION)))
        Quit( RETURN_FAIL );

    PPBase = (struct PPBase *)OpenLibrary("powerpacker.library",0);

    if(!(plock = LockPubScreen("Workbench")))
        Quit( RETURN_FAIL );
    ns.Width  = nw.Width  = plock->Width;
    ns.Height = nw.Height = plock->Height;
    ns.ViewModes = plock->ViewPort.Modes;
    UnlockPubScreen(NULL,plock);

    if(!(VW_scr = OpenScreenTagList(&ns,(struct TagItem *)&NewScreenTags[0])))
        Quit( RETURN_FAIL );
    nw.Screen = VW_scr;
    if(!(VW_wnd = OpenWindow(&nw)))
        Quit( RETURN_FAIL );
    ShowTitle(VW_scr,FALSE);
    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 );

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

__regargs void Quit( long code )
{
    CloseConsole();
    if(VW_text)
        FreeAscii(VW_text);
    if(VW_freq)
        FreeAslRequest(VW_freq);
    if(VW_wnd) {
        VW_proc->pr_WindowPtr = VW_wdptr;
        CloseWindow(VW_wnd);
    }
    if(VW_scr)
        CloseScreen(VW_scr);
    if(NoFragBase)
        CloseLibrary(NoFragBase);
    if(VW_fargs)
        FreeArgs(VW_fargs);
    exit(code);
}

__regargs 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);
}

__regargs 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);
}

__regargs 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 v1.0 © 1991 Jaba Development");

    if(request == TRUE) {
        RequestTags2[1] = VW_wnd;
        RequestTags2[3] = Dir;
        RequestTags2[5] = File;
        ret = AslRequest(VW_freq,(struct TagItem *)&RequestTags2[0]);
        if(ret) {
            Dir  = VW_freq->rf_Dir;
            File = VW_freq->rf_File;
            strcpy(VW_name,Dir);
            if(VW_name[strlen(VW_name)-1] != ':' &&
               VW_name[strlen(VW_name)-1] != '/' &&
               strlen(VW_name))
                strcat(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.v1.0.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;
}

__regargs 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));
}

__regargs 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();
}

__regargs 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();
}

__regargs 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);
}

__regargs 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;
                    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(FirstOccurrence(VW_text,VW_fbuf,&VW_search,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);
}

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;
}

void PrintFile( void )
{
    UBYTE   errl[31];

    if(!VW_text)    return;

    if(VW_pmode == PRT_BLOCK) {
        if(!VW_blk[VW_pmark].TopLine || !VW_blk[VW_pmark].BottomLine) {
            sprintf(errl,Lines[4],VW_pmark+1);
            ErrorLine(errl);
            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;
    UBYTE                errl[31];

    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);
}

__regargs void Sleep( BOOL preserve )
{
    struct MsgPort          *port = 0L;
    struct IOStdReq         *req  = 0L;
    ULONG                    dev  = 1L, mask = -1L;

    if(FindPort(Lines[0])) {
        ErrorLine("A View is already sleeping !");
        return;
    }

    if(!(port = CreatePort(Lines[0],0)))
        goto CleanExit;
    if(!(req = CreateStdIO(port)))
        goto CleanExit;
    if((dev = OpenDevice("input.device",0,(struct IORequest *)req,0)))
        goto CleanExit;
    if((mask = AllocSignal(-1L)) == -1L)
        goto CleanExit;

    VW_data.ViewSigMask = 1 << mask;
    VW_data.ViewTask    = (struct Task *)VW_proc;

    VW_proc->pr_WindowPtr = VW_wdptr;

    CloseConsole();
    CloseWindow(VW_wnd);
    CloseScreen(VW_scr);
    VW_wnd = VW_scr = 0L;

    if(!preserve) {
        if(VW_text) FreeAscii(VW_text);
        VW_text = 0L;
    }

    VW_int.is_Data          = (APTR)&VW_data;
    VW_int.is_Code          = (void *)HandlerStub;
    VW_int.is_Node.ln_Pri   = 51;
    VW_int.is_Node.ln_Name  = "ViewSleepy-Handler";

    req->io_Command         = IND_ADDHANDLER;
    req->io_Data            = (APTR)&VW_int;
    DoIO((struct IORequest *)req);

    while(1) {
        Wait(VW_data.ViewSigMask);

        if(VW_data.Flush) {
            if(VW_text) FreeAscii(VW_text);
            VW_text = 0L;
        } else
            break;
    }

    req->io_Command         = IND_REMHANDLER;
    req->io_Data            = (APTR)&VW_int;
    DoIO((struct IORequest *)req);

    if(VW_data.View) {
        if(!(VW_scr = OpenScreenTagList(&ns,(struct TagItem *)&NewScreenTags[0]))) {
            VW_data.Quit = TRUE;
            goto CleanExit;
        }
        nw.Screen = VW_scr;
        if(!(VW_wnd = OpenWindow(&nw))) {
            VW_data.Quit = TRUE;
            goto CleanExit;
        }
        ShowTitle(VW_scr,FALSE);
        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()) {
            VW_data.Quit = TRUE;
            goto CleanExit;
        }
        if(!VW_text)
            LoadFile(TRUE);
        else
            InfoLine();
        DisplayText();
    }
CleanExit:
    if(mask != -1L)     FreeSignal(mask);
    if(!dev)            CloseDevice((struct IORequest *)req);
    if(req)             DeleteStdIO(req);
    if(port)            DeletePort(port);
    if(VW_data.Quit)    Quit( RETURN_OK );
}

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

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

__regargs 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;
}

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

    GetRes();
    ConvertKeyTab();

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

    while(1)
    {
        Percentage();
        WaitPort(VW_wnd->UserPort);
        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 );
                    SteadyRepeat(VW_wnd->UserPort);
            }
        }
    }
    return(0);
}

__regargs 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;
    }
}

__regargs 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);
}

__regargs void JumpMark( UWORD mark )
{
    struct Line *line;
    UBYTE        errl[31];

    if(!VW_text)    return;

    if(!VW_blk[mark].TopLine || !VW_blk[mark].BottomLine) {
        sprintf(errl,Lines[4],mark+1);
        ErrorLine(errl);
        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();
}

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