*-----------------------------------------------------*
*                CType Version 2.02                   *
*                                                     *
*      Copyright February 1990 - by Bill Nelson       *
*             Midnight Logic Software                 *
*                                                     *
*      This is a FREELY REDISTRIBUTABLE PROGRAM       *     
*                                                     *
* Please report any bugs or problems you find         *
* (there PROBABLY are some!) - and any suggestions    *
* for further functionality would also be welcomed.   *
* Happy Assembling!                                   *
*                                                     *
*   v 2.02          00:00:01             10/05/90     *
*                                                     *
*-----------------------------------------------------*

PUR          EQU      1
WBC          EQU      1          ; will need console if from WB
REQ          EQU      1          ; want pure code, Req startup
VS           EQU   1300          ; amount of variable space needed
                                 ; alloc'd in ReqPurStart.ASM

   bra       Start               ; Jump into ReqPurStart.ASM

   INCLUDE  "INCLUDES:Header.ASM"

Quit         EQU      0          ; some EQUates for later readability
Up           EQU      1
Down         EQU      2
Top          EQU      3
Bottom       EQU      4
Again        EQU      5   
Assist       EQU      6
PageUp       EQU      7
PageDown     EQU      8
NewFile      EQU      9
SizeIt       EQU     10
ScrollR      EQU     11
ScrollL      EQU     12
ChangeTab    EQU     13
Next         EQU     14

***  Variables as offsets from a5  ***

LineBuff     EQU      0          ; each line as output  (400 chars)
KeyBuff      EQU    400          ; filename              (80 chars)
Control      EQU    480          ; user requests etc     (36 chars)
CBuff        EQU    516          ; 1 char user inputb     (4 chars)
FileReq      EQU    520          ; PTR to FilReq struct       LONG
FilePTR      EQU    524          ; PTR to File                LONG
FileLok      EQU    528          ; PTR to FileLok             LONG
fib_PTR      EQU    532          ; PTR to fib_struct memory   LONG
FileMemBuf   EQU    536          ; PTR to filebuff memory     LONG
FileChars    EQU    540          ; Number of chars read       LONG
FileSize     EQU    544          ; FileSize                   LONG
EdNum        EQU    548          ; Editor entry size          LONG
EdPTR        EQU    552          ; Editor entry file PTR      LONG
PRTFile      EQU    556          ; PRT file handle            LONG
CharCount    EQU    560          ; PTR to char to read in Buf LONG
LinePtr      EQU    564          ; PTR to start of line       LONG
RawHnd       EQU    568          ; raw window handle          LONG
pf_PTR       EQU    572          ; PTR to Pref struct         LONG
FileNm       EQU    576          ; PTR to filename            LONG
OldDir       EQU    580          ; LOCK on old directory      LONG
SrchOK       EQU    584          ; "was valid Search" flag    LONG
EndLine      EQU    588          ; end of current line        LONG
CharCounter  EQU    592          ; charcounter                LONG
ColTotal     EQU    696          ; total columns              LONG
EOL          EQU    600          ; place EOL last found at    LONG
NumLines     EQU    604          ; display lines avail        LONG
NumFiles     EQU    608          ; num files specified        LONG
CurrentFile  EQU    612          ; number of current file     LONG
CurPosn      EQU    616          ; current position in file   LONG
LastPosn     EQU    620          ; last position in file      LONG
PageBot      EQU    624          ; current page bottom        LONG
PageTop      EQU    628          ; current page TOP           LONG
HereNow      EQU    632          ; midline posn               LONG
StartLine    EQU    636          ; start of above line        LONG
HunFileSize  EQU    640          ; 1/100 of filesize          WORD
MUSTFormat   EQU    642          ; MUST FORMAT flag           BYTE
FormatMode   EQU    643          ; State of format mode       BYTE
IsMultiArg   EQU    644          ; flag "in multi-arg mode"   BYTE
RowSizeChg   EQU    645          ; num extra rows             BYTE
ColSizeChg   EQU    646          ; num extra cols             BYTE
LaceTogl     EQU    647          ; whether interlaced         BYTE
EndFlag      EQU    648          ; EOF flag                   BYTE
TopFlag      EQU    649          ; TOF flag                   BYTE
SmallFile    EQU    650          ; "is small file" flag       BYTE
SrchType     EQU    651          ; "type of last search" flag BYTE
PrtScFlag    EQU    652          ; "print screen" flag        BYTE
TabSize      EQU    653          ; user tabsize preference    BYTE
SmallWindow  EQU    654          ; whether undersize window   BYTE
RawName      EQU    655          ; OpenWin string       (85 chars)
Wide         EQU    662          ;
High         EQU    666          ;
FName        EQU    677          ; place to jam in file's name
PosPrompt    EQU    746
PromptPos    EQU    747          ; prompt string        (78 chars)
CurPos       EQU    756
KByteTot     EQU    766
ModeMarker   EQU    787
SPosPrompt   EQU    832          ; SHORT prompt string  (24 chars)
SPromptPos   EQU    833          ;
DirBuff      EQU    856          ; storage for DIR string
FileBuff     EQU    988          ; storage for FILE string
PathName     EQU   1020          ; storage for concat of above
TextReq      EQU   1182          ; TextRequester struct
GetLong      EQU   1228          ; GetLongStruct
GetString    EQU   1262          ; GetStringStruct
                                 ; TOTAL of 1298 bytes
                                 ; EQU'd above for
                                 ; startup to Alloc correctly


   EvenPC

***  The PROGRAM (at last!)  ***


_Main
   lea       TextReq(a5),a0
   move.w    #$ffff,TR_KeyMask(a0); set requester to hot keys
   move.w    #3,TR_textcolor(a0)
   move.b    #8,TabSize(a5)      ; initial setting!
   move.l    EndFromWB(a5),d0    ; was this started from WB
   beq.s     CLIEntry            ; no, do the CLI stuff
   move.l    WBMsg(a5),a0        ; yes, set WBMsg up for offset access
   move.l    sm_NumArgs(a0),d3   ; how many args were provided
   subq      #1,d3               ; decrement down to number of FILES
   beq.s     NoArgs              ; were no files, set CurrentDir & call request
   move.l    d3,NumFiles(a5)     ; save number of files requested
   move.l    #1,CurrentFile(a5)  ; and start on first one...
   bra       NextWBArg

NoArgs
   move.l    sm_ArgList(a0),a2   ; get start of ArgList
   move.l    (a2),d1             ; stick it in d1
   DosCall   CurrentDir          ; and set our current dir to location of
   move.l    d0,OldDir(a5)       ; CType (and save where we were)
   bra.s     NoCLIArgs
CLIEntry
   move.l    CmdLen(a5),d0       ; Check if user entered filename
   cmpi.b    #1,d0               ; on the command line
   beq.s     NoCLIArgs           ; if not, exit with explanation
   move.l    Command(a5),a1      ; check if ? is parameter
   cmpi.b    #'?',(a1)           ;
   beq.s     Usage
   move.l    Command(a5),a0      ; set File buffer to match
   lea       FileBuff(a5),a1
   bsr       CopyString
   move.l    Command(a5),d1      ; or set it up for CheckExists
   move.l    d1,FileNm(a5)       ; and store pointer for later access
   move.l    #1,NumFiles(a5)     ; number of files to display
   move.l    #1,CurrentFile(a5)  ; and start off on first one
   bra.s     GoGetIt
Usage
   TxtReq    UseTxt(pc),ResumeTxt(pc)
NoCLIArgs
   bsr       GetFileName         ; and get filename from user (?)
GoGetIt
   bra       OpenFile
UseTxt
   dc.b      10,' Enter an (optional) filename ',10
   dc.b      10,' or just start the program up! ',0
   EvenPC

NextWBArg
   Zero      d2                  ; clear out d2
   move.l    CurrentFile(a5),d0  ; num of current file as counter
OffSetLoop
   add.l     #wa_SIZEOF,d2       ; add size of WBArg in d2, as offset to arg
   subq      #1,d0               ; decrement cur file counter
   bne.s     OffSetLoop          ; not on it yet - more offset needed
   move.l    WBMsg(a5),a0        ; yes, set WBMsg up for offset access
   move.l    sm_ArgList(a0),a2   ; setup arglist for offset access
   move.l    0(a2,d2),d1         ; ptr to directory lock into d1
   DosCall   CurrentDir          ; change to directory of specified file
   move.l    d0,OldDir(a5)       ; and save where we came from
   move.l    wa_Name(a2,d2),d1   ; put PTR to filename in d1
   move.l    d1,FileNm(a5)       ; and store for opening file after getting lock
   move.l    d1,a0
   lea       FileBuff(a5),a1     ; and copy Filename into buffer for title
   bsr       CopyString
   bra       OpenFile            ; and skip to the Openfile routine

GetFileName
   move.l    FileReq(a5),d0      ; already HAVE one?
   bne.s     GetFileAgain        ; yup - DON'T start another!
   AllocPubMem #frq_SIZEOF       ; get memory for filerequester
   tst.l     d0
   beq       MemFail
   move.l    d0,FileReq(a5)      ; store PTR to struct
   move.l    d0,a0
   lea       DirBuff(a5),a1
   move.l    a1,frq_Dir(a0)      ; ptr to buff for directory
   lea       FileBuff(a5),a1
   move.l    a1,frq_File(a0)     ; ptr to buff for filename
   lea       PathName(a5),a1
   move.l    a1,frq_PathName(a0) ; ptr to buff for complete pathname
GetFileAgain
   move.l    FileReq(a5),a0      ; put it in a0
   move.l    #0,frq_Flags(a0)    ; clear flags
   lea       ReqTitle(pc),a1     ; give it a title
   move.l    a1,frq_Title(a0)    ;
   move.w    #40,frq_numlines(a0)
   move.w    #3,frq_dirnamescolor(a0)
   move.w    #2,frq_devicenamescolor(a0)
   or.l      #FRQEXTSELECTM!FRQCACHINGM!FRQLOADINGM,frq_Flags(a0)
   ReqCall   FileRequester       ; and call it up
   tst.l     d0                  ; was it CANCELled?
   beq       GoNow               ; yes - wants out...
   move.l    FileReq(a5),a2      ; or find out what
   move.l    frq_ExtendedSelect(a2),d1
   beq.s     NoExtend            ; no extend select - 1 file only

NumFilesSelect
   move.b    #1,IsMultiArg(a5)   ; we are in Multi-Arg mode
   move.l    d1,a2               ; First ESSStruct in a2
   Zero      d2                  ; start counter at zero
1$
   move.l    es_NextFile(a2),a2  ; get next structure
   addq      #1,d2               ; add 1 to counter
   cmpi.l    #0,a2               ; is this link ptr zero?
   bne.s     1$                  ; nope? do it again
   move.l    d2,NumFiles(a5)     ; yup - counter = # of files
   move.l    #1,CurrentFile(a5)  ; and we start on first file

MultiArgs
   move.l    CurrentFile(a5),d2  ; current file is?
   move.l    FileReq(a5),a0      ; get FileReq Struct
   move.l    frq_ExtendedSelect(a0),a2
   subq      #2,d2               ; 
   blt.s     BuildName           ; was first file, HAVE right struct
GetStruct
   move.l    es_NextFile(a2),a2  ; get next struct
   cmpi.l    #0,a2               ; check if zero (counter wrong somehow?)
   beq.s     BuildName
   dbra      d2,GetStruct        ; do again if counter not reached
BuildName
   lea       DirBuff(a5),a0      ; copy DIRname into Pathname
   lea       PathName(a5),a1
   bsr       CopyString
   lea       PathName(a5),a0
   subq      #1,a1               ; back up over null
   cmp.l     a0,a1               ; Dir name was null?
   beq.s     NoSep
   cmp.b     #':',-(a1)          ; was last char of dir a ':' ?
   bne.s     1$
   addq      #1,a1               ; return a1 to correct posn
   bra.s     NoSep               ; no other sep needed
1$
   addq      #1,a1               ; return a1 to correct posn
   move.b    #'/',(a1)+          ; put in dir separator

NoSep
   lea       es_FileName(a2),a0  ; get file name
   bsr       CopyString          ; into PathName for open
   lea       es_FileName(a2),a0
   lea       FileBuff(a5),a1     ; and into FileBuff
   bsr       CopyString          ; so title reflects right file!
   bra.s     SetName

NoExtend
   move.b    #0,IsMultiArg(a5)   ; no multiargs active
   move.l    #1,NumFiles(a5)     ; number of files we know of
   move.l    #1,CurrentFile(a5)  ; and this file's number

SetName
   lea       PathName(a5),a0     ; load name
   move.l    a0,d1               ; into d1 for _CheckExists
   move.l    d1,FileNm(a5)       ; and store for later
   rts
   
***  Open the file  ***

OpenFile
   tst.l     d1                  
   beq       NextOrExit  
   PushReg   d1
   bsr       _ShutDown
   PullReg   d1
   bsr       _CheckExists        ; try for Lock on file
   tst.l     d0
   beq.s     NoFileFound         ; no exist - I guess we lost it :-(
   move.l    d0,FileLok(a5)      ; stash it for other uses!
   bsr       _GetFileSize        ; find out the file size - how much MEM?
   tst.l     d0
   beq       OpenTrouble         ; couldn't get the filesize (mem?)
   move.l    d0,FileSize(a5)     ; store for later - also in d0 to
   AllocPubMem  d0               ; alloc enough mem for file buffer
   tst.l     d0                  ; See if call made it
   beq       MemFail             ; or leave...
   move.l    d0,FileMemBuf(a5)   ; otherwise, store PTR to memory
                                 ; (automatically LONG aligned by EXEC)
   move.l    FileNm(a5),d1       ; put PTR to filename in d1
   move.l    #MODE_OLDFILE,d2    ; for reading
   DosCall   Open
   tst.l     d0                  ; see if a handle was returned (success)
   beq.s     OpenTrouble         ; No? Skip the rest
   move.l    d0,FilePTR(a5)      ; or store handle if successful
   bsr       _SetUpStrings       ; copy our modifiable strings to work area
   bra       CalcKBytes          ; and get on with it

NoFileFound
   TxtReqCt  NoFileMsg(pc),ResumeTxt(pc),FileBuff(a5)
   bra       NextOrExit
NoFileMsg
   dc.b      10,' Could not locate file ',10,10,' <%s> ',0
   EvenPC

OpenTrouble
   TxtReq    OpenTroubleMsg(pc),ResumeTxt(pc)
   bra.s     FixFileLok
OpenTroubleMsg
   dc.b      10,' Could not open file ',10,0
   EvenPC

MemFail
   TxtReq    MemFailMsg(pc),ResumeTxt(pc)
   bra.s     FixFileLok
MemFailMsg
   dc.b      10,' Not enough memory! ',10,0
   EvenPC

FixFileLok
   move.l    FileLok(a5),d1      ; get the lock
   beq.s     1$                  ; wasn't one, skip it!
   DosCall   UnLock              ; free it up
1$
   move.l    #0,FileLok(a5)      ; and zero the space
   bra       NextOrExit

***  Various Calculations for later  ***


CalcKBytes
   Zero      d0                  ; clear out the regs I use here
   Zero      d1                  ;
   move.l    FileSize(a5),d0     ; total filesize into d0
   cmpi.l    #9999,d0            ; 
   ble.s     SmallerFile         ; less than 10000 bytes, display as such
   divu      #1024,d0            ; divide by bytes in a KByte
   move.w    d0,d1               ; move only the word value to d1
   swap      d0                  ; flip upper to lower word in d0
   cmpi.w    #512,d0             ; is remainder above 1/2 K?
   blt.s     1$                  ; if less, skip this next
   addq      #1,d1               ; round up if greater than 1/2K
1$
   lea       KByteTot(a5),a0     ; stuff it into string for end of page
   bsr       _ASCIIConv          ; in ASCII :-)
   bra.s     CalcForPercent

SmallerFile
   move.l    d0,d1               ; put filesize in d1
   lea       KByteTot(a5),a0     ; stuff it into string for end of page
   bsr       _ASCIIConv          ; in ASCII
   addq      #1,a0               ; add 1 to point past end of number
   move.b    #' ',(a0)           ; stuff space over the "K" in KBytes :-)

CalcForPercent
   Zero      d0                  ; clear out REG we need
   Zero      d1                  ; to ensure "clean" result
   move.l    FileSize(a5),d0     ; get filesize/100
   divu      #100,d0             ; to make % calculation fit in WORD
   move.w    d0,d1               ; thus allowing DIVU to work!
   beq.s     1$                  ; unless is ZERO result! (no GURU 5 please!)
   move.w    d1,HunFileSize(a5)  ; store it for calculation done at end of page
   bra.s     GetThePrefs
1$
   move.w    #1,HunFileSize(a5)  ; never less than 1 for divisor!
   move.b    #1,SmallFile(a5)    ; and mark as file that needs no further calc!

*** Get data on the WorkBench screen ***


GetThePrefs
   bsr       _GetPreferences     ; find out current Prefs settings
   tst.l     d0                  ; did it work?
   beq       Error               ; no - get out

FillInParams
   Zero      d1                  ; make sure ONLY our value in d1 
   move.b    ColSizeChg(a5),d1   ; change in width (pixels)
   addi      #640,d1             ; add in 640
   lea       Wide(a5),a0         ; and get the ASCII equivalent
   bsr       _ASCIIConv          ; and write it into the string we later
   lea       Wide(a5),a0         ; pass to the OPEN call for a window
   move.b    #'/',(a0)           ; add in the '/' in the right place!
   Zero      d1       
   move.b    RowSizeChg(a5),d1   ; same thing for height (pixels)
   addi.l    #200,d1             ; add the standard height
   move.b    LaceTogl(a5),d0     ; interlace on?
   beq.s     1$                  ; no, we have the value
   add.l     d1,d1               ; yes. multiply by 2
1$
   lea       High(a5),a0         ; and stuff it in the string as well
   bsr       _ASCIIConv          ; with the same "brute force" technique
   lea       High(a5),a0
   move.b    #'/',(a0)           ; with the / separator
SetUpTitle
   lea       FileBuff(a5),a0     ; PTR to filename in a0
   move.l    a0,a2               ; and in a2 for difference
   lea       FName(a5),a1        ; and destination for string in a1
   Zero      d1                  ; initialize counter
LengthChk
   addq      #1,d1               ; increment counter
   tst.b     (a2)+               ; look for end of string
   bne.s     LengthChk
   cmp       #24,d1              ; was it more than 24 chars
   ble.s     MoveName            ; nope - just copy it up
MvLeft
   subq.l    #6,a1               ; back up over "File: " entry
MoveName
   bsr       CopyString          ; copy the string up
   move.b    #' ',-(a1)          ; put space over the zero byte

***  Open a window for I/O (of size we now know)  ***

OpenWin
   lea       RawName(a5),a0
   move.l    a0,d1               ; Set up a RAW window for single keystroke eval
   move.l    #MODE_NEWFILE,d2    ; always as a new file
   DosCall   Open                ; using the string we built above
   tst.l     d0                  ; see if a handle was returned (success)
   beq       Error               ; CAN'T open it - skip rest of it
   move.l    d0,RawHnd(a5)       ; got it, store it for output later
   DosPrt    RawHnd(a5),SetMouse(pc)
   bsr.s     CalcCols
   bra       ReadFile

CalcCols
   PushReg   a2-a3
GetResponse
   DosPrt    RawHnd(a5),GetWinStat(pc)
   move.l    #1000000,d2         ; wait 1 sec for incoming
   move.l    RawHnd(a5),d1       ; in our window
   DosCall   WaitForChar         ; we don't BUSY LOOP looking, but
   DosRd     RawHnd(a5),KeyBuff(a5),#20 ; we want all that's useful
   lea       KeyBuff(a5),a0
   move.b    (a0)+,d0            ; get first char
   cmpi.b    #$9b,d0             ; is it CSI?
   bne       GetResponse       
   move.b    (a0)+,d0            ; get a char
   cmpi.b    #'1',d0             ; is it a 1?
   bne       GetResponse       
   move.b    (a0)+,d0            ; get a char
   cmpi.b    #';',d0             ; is it a separator
   bne       GetResponse       
   move.b    (a0)+,d0            ; get a char
   cmpi.b    #'1',d0
   bne       GetResponse       
   move.b    (a0)+,d0            ; get a char
   cmpi.b    #';',d0
   bne       GetResponse       
   move.l    a0,a2               ; made it this far, must be Status report!
   lea       PromptPos(a5),a1    ; set ptr to string for placing prompt
WorkLoop
   move.b    (a0),d0             ; get character
   cmpi.b    #';',d0             ; see if it is a separator
   beq.s     MarkIt              ; first parameter complete
   cmpi.b    #' ',d0             ; space after end of 2nd parameter
   beq.s     DoneBoth            ; 2nd parameter complete
   move.b    (a0)+,(a1)+         ; pop char into string for posn'g prompt
   bra.s     WorkLoop            ; get next character
MarkIt
   move.l    a0,a3               ; "store" PTR to next parameter (+1 needed!)
   addq      #1,a3               ; so we can convert them to values
   move.b    #0,(a0)             ; put a null after 1st parameter
   lea       KeyBuff(a5),a1      ; and dummy dest so we can re-use loop :-)
   bra.s     WorkLoop            ; (well - already knew that 1,1 was top corner!)
DoneBoth
   move.b    #0,(a0)             ; put null after 2nd parameter
   move.l    a2,a0               ; ptr to 1st param in a0
   bsr       _ASCII2Val          ; and convert it to value
   subq      #2,d1               ; less 1 for Prompt, and 1 for DBRA!
   ble       GetResponse         ; if 0 or less, wait for another event :-)
   move.l    d1,NumLines(a5)     ; and we have number of lines
   move.l    a3,a0               ; ptr to 2nd param
   bsr       _ASCII2Val          ; convert it to a value
   move.l    d1,ColTotal(a5)     ; we have number of useable columns
   cmp.l     #61,d1              ; smaller than normal prompt string?
   bge.s     1$
   move.b    #1,SmallWindow(a5)  ; mark for SMALL prompt only!
   bra.s     2$
1$
   move.b    #0,SmallWindow(a5)  ; mark as big enough window
2$
   lea       PromptPos(a5),a0    ; copy positioning to other
   lea       SPromptPos(a5),a1   ; prompt string
   move.b    (a0)+,(a1)+
   move.b    (a0)+,(a1)+
   PullReg   a2-a3               ; restore our regs
   rts

***  Read the file in  ***

ReadFile
   DosRead   FilePTR(a5),FileMemBuf(a5),FileSize(a5)
   tst.l     d0
   bgt.s     KeepGoing           ; greater than 0, is length of useful file
   move.l    FilePTR(a5),d1      ; or shut it down.
   DosCall   Close
   move.l    FileLok(a5),d1      ; better not forget to UNLOCK the file!
   DosCall   UnLock              ; so we do it now...
   move.l    #0,FileLok(a5)      ; and clear the storage area
   TxtReq    NoReadFileMsg(pc),ResumeTxt(pc)
   bra       NextOrExit
NoReadFileMsg
   dc.b      10,' File unreadable or empty ',10,0
   EvenPC

KeepGoing
   move.l    d0,FileChars(a5)    ; tells us how many were read
   move.l    FilePTR(a5),d1      ; STILL no trust :-)
   DosCall   Close               ; won't need it again
   move.l    FileLok(a5),d1      ; better not forget to UNLOCK the file!
   DosCall   UnLock              ; so we do it now...
   move.l    #0,FileLok(a5)      ; and clear the storage (for later use!)

***  Check file format  ***

FormatCheck
   move.l    FileMemBuf(a5),a2   ; Start of buffer
   move.l    FileChars(a5),a3    ; Number of chars it contains
   adda.l    a2,a3               ; End of buffer now in a3
   Zero      d6                  ; track char/line

InitScan
   move.b    (a2)+,d0            ; move byte to d0, and increment a2
   cmpi.b    #10,d0              ; is LF character?
   beq.s     1$
   cmpi.b    #13,d0              ; is CR character?
   bne.s     2$
1$
   Zero      d6
   bra.s     InitScan       
2$
   cmpi.b    #$E,d0              ; is SHIFT OUT char?
   beq.s     IsBinary            ; likely binary file
   cmpi.b    #127,d0             ; is highbit set?
   bgt.s     IsBinary            ; likely not readable
   addq      #1,d6               ; up count of chars this line
   cmpi      #512,d6             ; more than 512 chars?
   bgt.s     LineTooLong         ; FORCE format mode!
   cmpa.l    a2,a3
   bgt       InitScan
   move.b    #0,MUSTFormat(a5)   ; made it this far - mark as OK
   bra       DisplayFile

LineTooLong
   move.b    #1,MUSTFormat(a5)   ; set both flags
   move.b    #1,FormatMode(a5)
   Zero      d7                  ; clear any format offset!
   lea       ModeMarker(a5),a0
   move.b    #'F',(a0)
   bra.s     DisplayFile

IsBinary
   TxtReq    NonASCIIMsg(pc),NoTxt(pc),YesTxt(pc)
   tst.l     d0
   bne       InitScan            ; keep testing (for long lines!)
   bra       NextOrExit
NonASCIIMsg
   dc.b      10,' Non ASCII characters found ',10,10,' Attempt to display anyway? ',10,0
   EvenPC

***  Display the file  ***

DisplayFile
   move.b    #1,TopFlag(a5)      ; mark us at TOF
   Zero      d7
   move.l    FileMemBuf(a5),a2   ; set a2 to start of buffer
   move.l    a2,PageTop(a5)
Pages
   bsr.s     _PageSetup
   bsr.s     _PageLoop
   bra.s     ReadingTime
   
_PageSetup
   lea       LineBuff(a5),a4     ; start of Buffer in a4
   move.l    a4,LinePtr(a5)      ; and in LinePtr variable
   move.l    NumLines(a5),d3     ; number of lines per page
   move.l    ColTotal(a5),d2     ; number of columns per page
   moveq     #12,d0
   bsr       _WrChar             ; Clear the screen
   move.l    a2,PageTop(a5)
   rts

_PageLoop
   Zero      d6                  ; set chars to display at zero
   bsr       _BuildLine          ; build normal text line
   bsr       _OutputLine         ; dump it to screen
   dbra      d3,_PageLoop        ; loop till NumLines on the screen
   rts

ReadingTime
   cmp.b     #1,SmallWindow(a5)  ; is this an underwidth window?
   bne.s     1$                  ; nope - do the prompt stuff
   DosPrt    RawHnd(a5),CursorOff(pc)
   DosPrt    RawHnd(a5),SPosPrompt(a5)
   bra.s     GetAKey
1$
   cmp.b     #1,SmallFile(a5)    ; was this a small file?
   beq.s     ForceIt             ; yes, skip the calcs!
   move.l    a2,d1               ; put current "position" in d1 for calcs
   sub.l     FileMemBuf(a5),d1   ; subtract start of buffer from d1
   divu      HunFileSize(a5),d1  ; divide by 1/100 of filesize for %
   swap      d1                  ; flip top and bottom of register      
   clr.w     d1                  ; to clear "remainder" - we don't care
   swap      d1                  ; flip it back and
   cmp.w     #100,d1             ; and check if over 100 (can only happen if
   ble.s     Prompt              ; file is under 1000 bytes)
ForceIt
   moveq     #100,d1             ; if it is, make it 100
Prompt
   lea       CurPos(a5),a0       ; force feed it to string PosPrompt
   bsr       _ASCIIConv
   DosPrt    RawHnd(a5),CursorOff(pc)   
   DosPrt    RawHnd(a5),PosPrompt(a5)
GetAKey
   bsr       _KeyHit             ; wait for a keystroke (sub returns action codes)
   tst.l     d0                  ; see if user wants out
   beq       GoNow               ; and exit if so
ReEntry                          ; entry point if from PrtScreen
   cmpi.b    #Up,d0              ; now we check all supported keystrokes
   bne.s     2$
   cmpa.l    a2,a3               ; at bottom?
   bgt.s     1$
   bsr       _BOF                ; redisplay as BOF
   bsr       _PageSetup
   bsr       _PageLoop
1$
   bra       _BackLine           ; now back up a line
2$
   cmpi.b    #Down,d0
   bne.s     3$
   bra       _ForLine            ; go ahead a line
3$
   cmpi.b    #Top,d0
   bne.s     4$
   bsr       _TOF                ; jump to top
   bra       Pages
4$
   cmpi.b    #Bottom,d0
   bne.s     5$
   bsr       _BOF                ; jump to bottom
   bra       Pages
5$
   cmpi.b    #Again,d0
   bne.s     6$
   move.l    PageTop(a5),a2      ; just redisplay with current params
   bra       Pages
6$
   cmpi.b    #Assist,d0
   bne.s     7$
   bsr       _Help               ; call HELP requester
   bra       GetAKey
7$
   cmpi.b    #PageUp,d0
   bne.s     8$
   bsr       _BackPage           ; back it up 1 page if possible
   bra       Pages
8$
   cmpi.b    #PageDown,d0
   bne.s     9$                  ; forward a page
   bra       Pages
9$
   cmpi.b    #SizeIt,d0          ; user requested size change?
   bne.s     10$             
   beq       _Resize             ; do it
10$
   cmpi.b    #ScrollR,d0         ; Scroll it Right
   bne.s     11$
   beq       _ScrollRight
11$
   cmpi.b    #ScrollL,d0         ; Scroll it Left
   bne.s     12$
   beq       _ScrollLeft
12$
   cmpi.b    #ChangeTab,d0       ; user requested tab size change?
   bne.s     13$
   beq       _TabSize            ; do it
13$
   cmpi.b    #Next,d0            ; hit ESC - wants another file?
   bne       Pages

***  Ways Out of program  ***

NextOrExit
   move.l    NumFiles(a5),d0     ; load it with numfiles
   move.l    CurrentFile(a5),d1  ; and our current file
   sub.l     d1,d0               ; 
   bgt.s     GetAnother          ; more to go...
AskAnother
   move.b    #0,IsMultiArg(a5)   ; we know we aren't in middle of multi
   TxtReq    AnotherMsg(pc),NoTxt(pc),YesTxt(pc)
   tst.l     d0
   beq.s     GoNow
   bra.s     GetNewName
AnotherMsg
   dc.b      10,' Display another file? ',10,0
   EvenPC

GetNewName
   bsr       GetFileName         ; and get another name
   bra       OpenFile

GetAnother
   add.l     #1,CurrentFile(a5)  ; increment number we're displaying
   move.b    IsMultiArg(a5),d1   ; we in multiargs?
   beq       NextWBArg           ; nope. get next WB arg
   bsr       MultiArgs           ; yup - get the name
   bra       OpenFile            ; and on we go

GoNow   
   move.l    EndFromWB(a5),d1    ; see if we started from WB
   beq.s     GoneNow             ; no, normal shutdown
   move.l    OldDir(a5),d1       ; yes, return our CurrentDir as was
   DosCall   CurrentDir          ; before we go and then
GoneNow
   bsr.s     _ShutDown           ; clean up everything that Startup doesn't
   bsr.s     _ShutDown2          ; yes, EVERYTHING
   Zero      d0
   rts                           ; GONE

Error
   bsr.s     _ShutDown
   bsr.s     _ShutDown2
   moveq     #20,d0              ; Set Error returncode
   rts

*** Subroutines ***

_ShutDown

ReturnMem
   move.l    FileMemBuf(a5),d0   ; ptr to buffer
   beq.s     CloseRaw            ; if not ptr... (!)
   move.l    d0,a1
   move.l    FileSize(a5),d0
   SysCall   FreeMem
   move.l    #0,FileMemBuf(a5)   ; and CLEAR it!
CloseRaw
   move.l    RawHnd(a5),d1       ; load Window handle into d1
   tst.l     d1                  ; if its NULL, we didn't get it open
   beq.s     Shut                ; so don't TRY to close it!
   DosCall   Close
   move.l    #0,RawHnd(a5)       ; clear ptr too!
Shut
   rts

_ShutDown2
   move.l    FileReq(a5),d0      ; ptr to FileReq struct
   beq.s     Shut2
   move.l    d0,a0
   ReqCall   PurgeFiles          ; release all assoc mem
   move.l    FileReq(a5),a1
   move.l    #frq_SIZEOF,d0      ; and the FileReq mem itself
   SysCall   FreeMem
   move.l    #0,FileReq(a5)      ; no ptr now!
Shut2
   rts

_SetUpStrings
   lea       RawName1(pc),a0     ; PTR to string in a0
   lea       RawName(a5),a1      ; PTR to where it goes
   bsr.s     CopyString          ; copy it up
   lea       PosPrompt1(pc),a0   ; same again
   lea       PosPrompt(a5),a1
   bsr.s     CopyString
   lea       SPosPrompt1(pc),a0  ; same again
   lea       SPosPrompt(a5),a1   ; and fall through to go on back
CopyString
   move.b    (a0)+,(a1)+         ; null-terminated strings are easy
   bne       CopyString          ; to move around in 680x0 asm!
   rts

_CheckExists                     ; enter with filePTR in d1
   moveq     #ACCESS_READ,d2     ; try it as a READ lock
   DosCall   Lock
   rts                           ; let caller evaluate results

_GetFileSize
   AllocChipMem #fib_SIZEOF      ; allocate memory for FileInfoBlock
   tst.l     d0                  ; (defined in DosEquates.ASM)
   beq.s     GotFileSize         ; no memory, exit with 0 in d0
   move.l    d0,fib_PTR(a5)      ; got mem, store PTR for later
   move.l    d0,d2               ; and set it as 1st parameter with
   move.l    FileLok(a5),d1      ; other parameter for Examine()
   DosCall   Examine
   tst.l     d0                  ; Boolean return
   beq.s     CloseFibMem         ; can't imagine WHY, but give back mem!
   move.l    fib_PTR(a5),a1      ; set up offset access for what we wanted
   move.l    fib_Size(a1),d0     ; now we have a FileSize as "return code"
CloseFibMem                      
   PushReg   d0                  ; save the "return code" for later
   move.l    fib_PTR(a5),a1      ; ptr to mem we allocated
   move.l    #fib_SIZEOF,d0      ; and size of the memory block
   SysCall   FreeMem             ; and give it back to the system
   PullReg   d0                  ; and reset return code
GotFileSize
   rts

_GetPreferences
   AllocChipMem #pf_SIZEOF       ; allocate memory for Preferences STRUCT
   tst.l     d0                  ; (defined in IntEquates.ASM)
   beq.s     GotPrefs            ; we didn't get it, d0 has "fail" return code
   move.l    d0,pf_PTR(a5)       ; and store for later
   move.l    d0,a0               ; and set it as 1st parameter with
   move.l    #pf_SIZEOF,d0       ; number of bytes we want from it
   IntCall   GetPrefs
   tst.l     d0                  ; Should return our PTR to buffer..
   beq.s     ClosePFMem          ; can't imagine WHY this would happen, but...
   move.l    pf_PTR(a5),a1       ; set up offset access for what we wanted!
   move.b    pf_RowSizeChange(a1),RowSizeChg(a5)
   move.b    pf_ColumnSizeChange(a1),ColSizeChg(a5)
   move.b    pf_LaceWB(a1),LaceTogl(a5)
   moveq     #1,d0               ; we got what we wanted, so return "success"
ClosePFMem                      
   PushReg   d0                  ; store return code for now
   move.l    pf_PTR(a5),a1       ; pointer to mem we got
   move.l    #pf_SIZEOF,d0       ; sizeof memory we got
   SysCall   FreeMem             ; give it back (we ARE well behaved!)
   PullReg   d0                  ; keep return code!
GotPrefs
   rts                           ; return with "Boolean" result

_BuildLine
   addq      #1,d6               ; up count of chars this line
   move.b    (a2)+,d0            ; get next character
   cmp.b     #12,d0
   beq.s     EOLine              ; was CLS, treat as LF
   cmpi.b    #$E,d0
   beq.s     EOLine              ; was SHIFT-OUT - pretend was EOL
   cmpi.b    #10,d0              ; (don't want ALT charset)
   beq.s     EOLine
   cmpi.b    #13,d0
   beq.s     CRatEOL
   cmp       d6,d2               ; end of displayable yet?
   bne.s     1$                  ; nope - skip checks
   cmpi.b    #1,FormatMode(a5)   ; is format mode active?
   beq.s     WordWrap            ; yup - go do word wrap
1$
   cmp.b     #9,d0               ; is it a TAB char?
   beq       HandleTab           ; if so, pop spaces in buffer
   move.b    d0,(a4)+
CheckEOF
   cmp.l     a2,a3               ; compare current posn (a2) w/ buffer end (a3)
   bgt       _BuildLine          ; back to get next character
   bra       GetOut              ; or leave if EOF
CRatEOL
   move.b    (a2)+,d0            ; check next character in string
   cmpi.b    #10,d0              ; for an LF char (maybe from PC?)
   beq.s     EOLine              ; yup - then just add LF to buffer
   subq      #1,a2               ; nope-  back up so char not missed
EOLine
   move.b    #10,(a4)
   rts

WordWrap
   cmpi.b    #32,d0              ; we on a space char?
   beq.s     WrapHere            ; 
   cmpi.b    #9,d0               ; was TAB char
   beq.s     EOLine              ; no need to expand it!
   subq      #1,a2               ; return a2 to char we have
   move.l    a2,EndLine(a5)      ; store this posn if needed
   move.l    d6,CharCounter(a5)  ; and the char counter
   move.l    a4,d1               ; and the buffer posn
WrapLoop
   subq      #1,d6               ; back up char counter
   cmpi.b    #1,d6               ; at beginning of line?
   beq.s     SkipWrap            ; yup...
   move.b    -(a2),d0            ; back up a char
   cmpi.b    #32,d0              ; got a space yet?
   beq.s     DoWrap              ; use as new EOLine
   cmpi.b    #9,d0               ; was it a tab char?
   beq.s     DoWrap              ; will do as a place to wrap
   subq      #1,a4               ; back up ptr into buffer
   bra.s     WrapLoop            ; try next char back
SkipWrap
   move.l    EndLine(a5),a2      ; put a2 back at end of line
   move.l    CharCounter(a5),d6  ; return d6 to num of chars
   move.l    d1,a4               ; and posn in buffer
   subq      #1,d6
   bra       EOLine              ; pop it out
DoWrap
   subq      #1,a4               ; back up buff ptr
   move.b    #10,(a4)            ; pop in EOL char
   addq      #1,a2               ; return a2 to char after break
   rts                           ; back to display line
ReplaceTab
   move.b    #10,-(a4)           ; put LF in buffer
   rts
WrapHere
   move.b    (a2)+,d0            ; check next char
   cmpi.b    #10,d0              ; is it a LF?
   beq       EOLine              ; done here
   cmpi.b    #13,d0              ; is it a CR?
   beq       CRatEOL             ; do the check
   cmpi.b    #32,d0              ; is another space?
   beq.s     WrapHere            ; try again
   subq      #1,a2               ; or back up so char not missed
   bra       EOLine              ; and stuff EOL in buffer

HandleTab
   PushReg   d3-d4               ; save working regs
   Zero      d3                  ; and clean 'em out
   Zero      d4                  ;
   move.b    TabSize(a5),d4      ; set up tab size for later
   beq.s     2$                  ; bypass divide by zero possibility!
   move.l    d6,d3               ; current "char pos'n used" counter
   subq      #1,d3               ; was "pre-incremented" in build loop
   add       d4,d3               ; add "max effect" of tab
   divu      d4,d3               ; divide by tabsize
   clr.w     d3                  ; to get the remainder
   swap      d3                  ;
   sub       d3,d4               ; subtract remainder from "max effect"
   subq      #1,d4               ; one off for dbra
   add       d4,d6               ; and add "actual effect" to chars used
   cmp.b     #1,FormatMode(a5)   ; is format mode in use?
   bne.s     1$
   cmp.l     d6,d2               ; are we out of chars?
   bge.s     1$                  ; nope
   move.b    #10,(a4)+           ; yup - put EOL in buffer
   sub       d4,d6               ; and remove tab effect on chars to display
   bra.s     2$
1$
   move.b    #' ',(a4)+
   dbra      d4,1$
2$
   PullReg   d3-d4               ; restore working registers
   bra       CheckEOF

GetOut
   cmpi.b    #1,d6
   bne.s     1$
   Zero      d6
   rts
1$
   move.b    #10,(a4)+
   rts

_OutputLine
   tst.l     d7                  ; any scroll Offset?
   beq.s     3$                  ; nope - ignore
   sub.l     d7,d6               ; yes, that many fewer to display
   bgt.s     2$                  ; does that make it 0 or less
1$
   moveq     #10,d0
   bsr       _WrChar             ; just write a LF
   bra.s     5$                  ; and skip other output
2$
   add.l     d7,LinePtr(a5)      ; add offset into buffer start addr
3$
   cmp.l     d2,d6               ; compare allowable chars with # to output
   ble.s     4$                  ; allowable number
   move.l    d2,d6               ; or MAKE it allowable number
   DosPrint  RawHnd(a5),LinePtr(a5),d6
   moveq     #10,d0
   bsr       _WrChar
   bra.s     5$
4$
   DosPrint  RawHnd(a5),LinePtr(a5),d6

5$
   lea       LineBuff(a5),a4
   move.l    a4,LinePtr(a5)
   rts

*** Get user requests  ***

_KeyHit
   move.l    #1000000,d2         ; wait 1 sec for reader to hit a key
   move.l    RawHnd(a5),d1       ; in our window
   DosCall   WaitForChar         ; we don't BUSY LOOP looking, but
   tst.l     d0
   beq       _KeyHit             ; we are determined to get one!
   DosRd     RawHnd(a5),Control(a5),#36  ; check it out for user's requests
   move.b    Control(a5),d0
   cmpi.b    #$9b,d0             ; is it CSI char?
   beq       ExtendKey           ; if so, check it out

   cmpi.b    #' ',d0             ; <SPACE> char
   beq       ForPage
   cmpi.b    #'3',d0             ; <PG DN> char on Numeric pad
   beq       ForPage

   cmpi.b    #8,d0               ; <BACKSPACE> char
   beq       BackPage
   cmpi.b    #'9',d0             ; <PG UP> char on Numeric pad
   beq       BackPage

   cmpi.b    #'?',d0             ; just a ? :-)
   beq       Help

   cmpi.b    #'q',d0
   beq       WantsNext
   cmpi.b    #'Q',d0
   beq       WantsNext
   cmpi.b    #27,d0              ; <ESC> char
   beq       WantsNext

   cmpi.b    #3,d0               ; <CTRL-C> char
   beq       WantsOut

   cmpi.b    #'r',d0
   beq       ScR
   cmpi.b    #'R',d0
   beq       ScR
   cmpi.b    #'6',d0             ; <RIGHT ARROW> key on Numeric pad
   beq       ScR

   cmpi.b    #'l',d0
   beq       ScL
   cmpi.b    #'L',d0
   beq       ScL
   cmpi.b    #'4',d0             ; <LEFT ARROW> key on Numeric pad
   beq       ScL

   cmpi.b    #13,d0              ; <RETURN> char
   beq       ForLine
   cmpi.b    #'2',d0             ; <DOWN ARROW> char on Numeric Pad
   beq       ForLine

   cmpi.b    #127,d0             ; <DELETE> char
   beq       BackLine
   cmpi.b    #'8',d0             ; <UP ARROW> char on Numeric pad
   beq       BackLine

   cmpi.b    #'t',d0
   beq       TOF
   cmpi.b    #'T',d0
   beq       TOF
   cmpi.b    #'<',d0
   beq       TOF
   cmpi.b    #'7',d0             ; <HOME> char on Numeric pad
   beq       TOF

   cmpi.b    #'b',d0
   beq       BOF
   cmpi.b    #'B',d0
   beq       BOF
   cmpi.b    #'>',d0
   beq       BOF
   cmpi.b    #'1',d0             ; <END> char on Numeric pad
   beq       BOF

   cmpi.b    #'e',d0
   beq       EDIT
   cmpi.b    #'E',d0
   beq       EDIT

   cmpi.b    #9,d0
   beq       Tab

   cmpi.b    #'/',d0             ; Case Sensitive search
   beq       SRCH
   cmpi.b    #'.',d0             ; Case INsensitive search
   beq       SRCHI

   cmpi.b    #'n',d0             ; repeat last search
   beq       ReSearch
   cmpi.b    #'N',d0
   beq       ReSearch

   cmpi.b    #'p',d0
   beq       PRT
   cmpi.b    #'P',d0             ; Print to ...
   beq       PRT

   cmpi.b    #'*',d0
   beq       PRTSc               ; PrintScreen

   cmpi.b    #'%',d0             ; Goto % in file
   beq       GOTO

   cmpi.b    #'f',d0
   beq       FMT   
   cmpi.b    #'F',d0             ; toggle format mode
   beq       FMT

   bra       _KeyHit             ; anything else we'll ignore!

ExtendKey
   move.b    Control+1(a5),d0    ; get next character
   cmpi.b    #'2',d0             ; MOUSE EVENT?
   beq       Mouse
   cmpi.b    #'1',d0             ; RESIZE EVENT?
   beq.s     RSize
   cmpi.b    #'?',d0             ; HELP Key?
   beq       Help                
   cmpi.b    #'0',d0             ; F1 Key?
   beq       Help                
   cmpi.b    #'6',d0             ; F7 Key?
   beq       PRTSc               
   cmpi.b    #'9',d0             ; F10 Key?
   beq       WantsOut               
   cmpi.b    #'A',d0             ; UP ARROW?
   beq       BackLine
   cmpi.b    #'T',d0             ; UP ARROW (shifted) ?
   beq       BackPage
   cmpi.b    #'B',d0             ; DOWN ARROW?
   beq       ForLine
   cmpi.b    #'S',d0             ; DOWN ARROW (shifted) ?
   beq       ForPage
   cmpi.b    #'C',d0             ; RIGHT ARROW?
   beq       ScR
   cmpi.b    #'D',d0             ; LEFT ARROW?
   beq       ScL
   cmpi.b    #' ',d0             ; LEFT or RIGHT ARROW (shifted) ?
   beq.s     ArrowChk
   bra       _KeyHit             ; don't WANT to know what else user hit!
ArrowChk
   move.b    Control+2(a5),d0
   cmpi.b    #'@',d0             ; RIGHT ARROW? (shifted of course)
   beq       BOF
   cmpi.b    #'A',d0             ; LEFT ARROW? (shifted)
   beq       TOF
   bra       _KeyHit             ; Ignoring all other keystrokes we got
                                 ; because an impatient user could have
                                 ; loaded us up with more requests than
                                 ; was intended!  Next call will write over
                                 ; whatever was in there...
RSize
   move.b    Control+2(a5),d0
   cmpi.b    #'2',d0
   beq       ReSize
   cmpi.b    #'6',d0             ; was it shifted F7?
   beq       PRT
   bra       _KeyHit
Mouse
   move.b    Control+5(a5),d0
   cmpi.b    #'1',d0             ; was it a button?
   bne.s     _NoGo               ; no - ignore it
   move.b    Control+6(a5),d0
   cmpi.b    #'0',d0             ; was it a button?
   bne.s     _NoGo               ; no - ignore it
   move.b    Control+7(a5),d0
   cmpi.b    #'4',d0
   bne.s     _NoGo               ; not it
LMB
   bra       ForPage             ; for the moment - advance a page!
_NoGo
   bra       _KeyHit

FMT
   cmp.b     #1,MUSTFormat(a5)   ; Is it LOCKED into format?
   beq.s     CantChange
   cmp.b     #1,FormatMode(a5)   ; is already IN format mode?
   beq.s     1$
   move.b    #1,FormatMode(a5)   ; nope - set it there
   lea       ModeMarker(a5),a0   ; change the marker in the prompt
   move.b    #'F',(a0)
   Zero      d7                  ; cancel any OFFSET value
   bra.s     2$
1$
   move.b    #0,FormatMode(a5)
   lea       ModeMarker(a5),a0   ; change marker in the prompt
   move.b    #'N',(a0)
2$
   moveq     #Again,d0           ; redisplay the page with new params
   rts
CantChange
   TxtReq    CantChangeMsg(pc),ResumeTxt(pc)
   moveq     #Again,d0
   rts
CantChangeMsg
   dc.b      10,' Cannot change mode on this file ',10,0
   EvenPC

Help
   moveq     #Assist,d0          ; pass "action code" in d0 to calling routine
   rts

ForPage
   cmpa.l    a2,a3
   ble       _KeyHit
   move.b    #0,TopFlag(a5)
   moveq     #PageDown,d0
   rts
BackPage
   cmpi.b    #1,TopFlag(a5)      ; are we already at the top?
   beq       _KeyHit             ; do nothing
   moveq     #PageUp,d0
   rts
TOF
   move.b    #1,TopFlag(a5)
   moveq     #Top,d0
   rts
BOF
   move.b    #0,TopFlag(a5)
   moveq     #Bottom,d0
   rts
WantsNext
   moveq     #Next,d0         
   rts
ForLine
   cmpa.l    a2,a3
   ble       _KeyHit             ; if EOF, do nothing
   move.b    #0,TopFlag(a5)      ; not EOF, say NOT TOF :-)
   moveq     #Down,d0
   rts
BackLine
   cmpi.b    #1,TopFlag(a5)
   beq       _KeyHit
   moveq     #Up,d0
   rts
ReSize
   move.l    #SizeIt,d0
   rts
ScR      
   cmp.b     #1,FormatMode(a5)   ; we in word wrap mode?
   beq       _KeyHit             ; do nothing
   moveq     #ScrollR,d0
   rts
ScL
   cmp.b     #1,FormatMode(a5)   ; we in word wrap mode?
   beq       _KeyHit             ; do nothing
   moveq     #ScrollL,d0
   rts
Tab
   moveq     #ChangeTab,d0
   rts
WantsOut
   moveq     #Quit,d0
   rts

***  Act on User Requests!  ***

_Help
   TxtReq    HelpMsg(pc),NoTxt(pc),YesTxt(pc)
   tst.l     d0
   beq.s     1$
   TxtReq    HelpMsg2(pc),NoTxt(pc),YesTxt(pc)
   tst.l     d0
   beq.s     1$
   bra.s     _Help
1$
   rts

_BackOnePage
   move.l    NumLines(a5),d3     ; Numlines as loop counter
   move.l    ColTotal(a5),d2     ; number of columns per page
   subq      #1,a2               ; back up so ON EOL
   addq      #1,d3               ; no dbra here :-)
ScanBack
   Zero      d4                  ; another counter (!)
   move.l    a2,EOL(a5)          ; store current EOL
   bsr.s     _BackScan           ; find previous EOL
   cmpi.b    #1,TopFlag(a5)      ; we at the top already?
   beq.s     GoTOF               ; yup - done this excercise!
   addq      #1,a2               ; step a2 past EOL char found
   Zero      d6                  ; zero the count of chars to display
   lea       LineBuff(a5),a4     ; point to start of buffer
   bsr       _BuildLine          ; build a display line
   addq      #1,d4               ; count times _BuildLine called
   cmp.l     EOL(a5),a2          ; are we back here?
   bgt.s     2$                  ; yup
1$
   Zero      d6                  ; zero the count of chars to display
   lea       LineBuff(a5),a4     ; point to start of buffer
   bsr       _BuildLine          ; build another..
   addq      #1,d4               ; keeping count
   cmp.l     EOL(a5),a2          ; back where we started yet?
   ble.s     1$                  ; nope - try again
2$
   subq      #1,a2               ; onto EOL char itself again
   cmp.l     d4,d3               ; compare lines taken with # to go
   beq.s     JustRight           ; done!!
   bgt.s     NotEnough           ; go for more
TooFar   
   sub.l     d3,d4               ; get diff OTHER way round
   subq      #1,d4               ; less 1 for dbra
   bsr.s     _BackScan           ; move on up
   addq      #1,a2               ; step past EOL char
1$
   Zero      d6                  ; zero the count of chars to display
   lea       LineBuff(a5),a4     ; point to start of buffer
   bsr       _BuildLine          ; step forward
   dbra      d4,1$               ; number of diff times
   rts
NotEnough
   sub.l     d4,d3               ; reduce # lines to go    
   bsr.s     _BackScan           ; set a2 back where it worked
   bra       ScanBack            ; and around again ..
JustRight
   bsr.s     _BackScan           ; put a2 back where it worked
   addq      #1,a2               ; 1 char after EOL
GoTOF
   rts
   

_BackScan
   cmpi.b    #10,-(a2)           ; is char a LF?
   bne.s     1$                  ; yup - return OK
   rts
1$
   cmpi.b    #13,(a2)            ; is it a CR?
   bne.s     3$                  ; nope - what else?
   addq      #1,a2               ; is next character
   cmpi.b    #10,(a2)            ; a LF?
   beq.s     2$
   subq      #1,a2               ; nope - return a2
   rts
2$
   subq      #1,a2               ; yup - return a2
   bra.s     _BackScan           ; and act as if didn't exist
3$
   cmpa.l    FileMemBuf(a5),a2   ; are we past start of file?
   bgt.s     _BackScan           ; nope - get next char
   move.l    FileMemBuf(a5),a2   ; yup - fix it
   move.b    #1,TopFlag(a5)
   rts

_BackPage
   move.l    PageTop(a5),a2      ; back up ptr to start of this page
   bsr       _BackOnePage        ; then up again, to show previous page
   rts

_TOF
   move.l    FileMemBuf(a5),a2   ; back up a2 to start of whole thing
   rts

_BOF
   movea.l   a3,a2               ; set a2 to end of buffer
   bsr       _BackOnePage        ; then back up a display page
   rts                           ; final page

_BackLine
   move.l    ColTotal(a5),d2     ; number of columns per page
   subq      #1,a2               ; put a2 ON EOL   
   moveq     #1,d3               ; set counter for one, and borrow the
   bsr       ScanBack            ; loop for here too :-)
   move.l    a2,PageBot(a5)      ; store new page END
   bsr       _BackOnePage        ; now set back full page
   cmpa.l    FileMemBuf(a5),a2   ; did we hit TOF?
   ble.s     SkipOutput          ; better skip it!
   DosPrt    RawHnd(a5),ScrDnHome(pc)
   move.l    a2,PageTop(a5)      ; mark new page top
   move.l    NumLines(a5),d3     ; number of lines per page
   move.l    ColTotal(a5),d2     ; number of columns per page
   lea       LineBuff(a5),a4     ; ptr to buffer
   move.l    a4,LinePtr(a5)      ; and to start of chars to display
   Zero      d6                  ; zero count of chars to display
   bsr       _BuildLine          ; build line in buffer
   bsr       _OutputLine         ; pump it out
   move.l    PageBot(a5),a2      ; restore new page END
   bra       ReadingTime         ; and onward
SkipOutput
   moveq     #Top,d0             ; simulate "TOF" keystroke
   bra       ReEntry             ; and continue
ScrDnHome
   dc.b      $9b,$54,$9b,'H',0   ; scroll down, and HOME cursor
   EvenPC

_ForLine
   DosPrt    RawHnd(a5),ClrLn(pc)
   lea       LineBuff(a5),a4
   move.l    a4,LinePtr(a5)
   move.l    NumLines(a5),d3
   move.l    ColTotal(a5),d2     ; number of columns per page
   Zero      d6                  ; zero Char counter
   bsr       _BuildLine          ; build line
   bsr       _OutputLine         ; display it
   move.l    a2,PageBot(a5)      ; save where we are
   bsr       _BackOnePage
   move.l    a2,PageTop(a5)      ; get new page TOP
   move.l    PageBot(a5),a2      ; back to bottom
   bra       ReadingTime

_PrevLine
   move.l    a2,HereNow(a5)      ; mark where we are
   bsr       _BackScan           ; find previous EOL
   addq      #1,a2               ; step 1 past it
PrevLoop
   move.l    a2,StartLine(a5)    ; store start of logical line
   lea       LineBuff(a5),a4     ; set up for
   move.l    a4,LinePtr(a5)
   move.l    NumLines(a5),d3
   move.l    ColTotal(a5),d2
   Zero      d6
   bsr       _BuildLine          ; building logical line
   cmp.l     HereNow(a5),a2      ; we now past point we found?
   ble.s     PrevLoop            ; nope - build another
   move.l    StartLine(a5),a2    ; yep, return with start of line
   rts

   
_ScrollRight
   cmp.l     #120,d7             ; less than 120 offset?
   bge.s     1$
   add       #10,d7              ; OK - add 10 to it
1$
   moveq     #Again,d0           ; and redisplay the page
   bra       ReEntry
   
_ScrollLeft
   tst.l     d7
   ble.s     1$                  ; already at original left margin?
   sub       #10,d7
1$
   moveq     #Again,d0
   bra       ReEntry             ; back to redisplay page

_TabSize
   lea       GetLong(a5),a0      ; get structure
   lea       TabTitle(pc),a1     ; give req a title
   move.l    a1,gl_titlebar(a0)
   move.l    #8,gl_defaultval(a0); 8 is the default tab size
   move.l    #2,gl_minlimit(a0)  ; and our limits
   move.l    #10,gl_maxlimit(a0)
   ReqCall   GetLong
   tst.l     d0                  ; if cancel, do nothing
   beq.s     NoChange
   lea       GetLong(a5),a0
   move.l    gl_result(a0),d0
   move.b    d0,TabSize(a5)      ; only .b to our var
NoChange
   moveq     #Again,d0           ; redisplay with new settings
   bra       ReEntry
TabTitle
   dc.b      ' TAB Size: ',0
   EvenPC

_Resize
   move.l    PageTop(a5),a2      ; set a2 back to current top of page
   bsr       CalcCols            ; reset new page size
   bra       Pages               ; and display new pagefull

*** Call the Editor ***

EDIT
   lea       EditName(pc),a0     ; get PTR to filename
   move.l    a0,d1               ; set it up for _CheckExists
   bsr       _CheckExists        ; to see if user HAS an editor preference!
   tst.l     d0
   bne.s     GetEditor           ; OK - it exists

AskEditor
   lea       LineBuff(a5),a0
   move.b    #0,(a0)
   lea       GetString(a5),a0    ; load structure
   lea       EdReqTitle(pc),a1   ; with values we want
   move.l    a1,gs_titlebar(a0)
   lea       LineBuff(a5),a1
   move.l    a1,gs_stringbuffer(a0)
   move.w    #30,gs_stringsize(a0)
   move.w    #28,gs_visiblesize(a0)
   move.w    #0,gs_versionnumber(a0)
   ReqCall   NewGetString        ; call requester for string
   tst.l     d0
   beq       EdTrouble           ; didn't get a valid response
   lea       LineBuff(a5),a0     ; OK - so figure how long string is
   Zero      d0
GetEdLen
   addq      #1,d0
   tst.b     (a0)+
   bne.s     GetEdLen
   subq      #1,d0
   bra.s     CallEditor          ; and go try to Execute() it
EdReqTitle
   dc.b      ' Editor Name: ',0
   EvenPC

GetEditor
   move.l    d0,FileLok(a5)      ; Lock in same place (not needed again)
   lea       EditName(pc),a0
   move.l    a0,d1
   move.l    #MODE_OLDFILE,d2    ; open up ENV:Editor and see what's there
   DosCall   Open     
   tst.l     d0
   bne.s     ReadEdName          ; 
   bra.s     EdTrouble

ReadEdName
   move.l    d0,EdPTR(a5)        ; store for closedown later
   DosRd     EdPTR(a5),LineBuff(a5),#79
   tst.l     d0                  ; read only as big as our buffer
   bne.s     CallEditor          ; if doesn't fit, won't find it!
   bra.s     EdTrouble

CallEditor
   lea       LineBuff(a5),a1     ; PTR to buff location
   add.l     d0,a1
   move.b    #' ',(a1)+          ; pop in a space
   move.l    FileNm(a5),a0       ; PTR to filename in a0
   bsr       CopyString
   lea       LineBuff(a5),a0     ; now set up whole string for
   move.l    a0,d1               ; Execute()
   Zero      d2                  ; no input specified
   move.l    StdOut(a5),d3       ; StdOut for output
   DosCall   Execute
   tst.l     d0
   bne.s     EndEdit
   bra.s     EdTrouble

EndEdit
   move.l    EdPTR(a5),d1        ; IF is PTR, THEN
   beq.s     DoneEdit
   DosCall   Close               ; close file
   move.l    #0,EdPTR(a5)        ; and clear storage!
   move.l    FileLok(a5),d1
   beq.s     DoneEdit            ; IF is lock, THEN
   DosCall   UnLock              ; unlock it
   move.l    #0,FileLok(a5)      ; and clear storage

DoneEdit
   moveq     #Again,d0           ; Redisplay from where we were
   rts

EdTrouble
   TxtReq    EdTroubleMsg(pc),ResumeTxt(pc)
   bra       EndEdit             ; and exit thru cleanup...
EdTroubleMsg
   dc.b      10,' Could not RUN your Editor ',10,0
   EvenPC

*** Printing options ***

PrtTitle
   dc.b      ' Choose PRINT Destination: ',0
   EvenPC

PRTSc
   move.b    #1,PrtScFlag(a5)        ; set flag for PrtScreen 

PRT
   PushReg   d2-d7
   lea       DirBuff(a5),a0
   move.b    #0,(a0)
   lea       FileBuff(a5),a1
   lea       PRTName(pc),a0
   bsr       CopyString
   move.l    FileReq(a5),a0      ; put it in a0
   move.l    #0,frq_Flags(a0)    ; clear flags
   lea       PrtTitle(pc),a1     ; give it a title
   move.l    a1,frq_Title(a0)    
   lea       DirBuff(a5),a1
   move.l    a1,frq_Dir(a0)      ; ptr to buff for directory
   lea       FileBuff(a5),a1
   move.l    a1,frq_File(a0)     ; ptr to buff for filename
   lea       PathName(a5),a1
   move.l    a1,frq_PathName(a0) ; ptr to buff for complete pathname
   or.l      #FRQEXTSELECTM!FRQCACHINGM!FRQSAVINGM,frq_Flags(a0)
   ReqCall   FileRequester       ; and call it up
   tst.l     d0
   beq       CancelPRT           ; was cancelled
   bsr       ChkDev              ; see if matches device name
   tst.l     d0                  ; if zero'd was no match
   bne       OverWrite           ; was match, treat as overwrite mode
   lea       PathName(a5),a0     ; diff num of chars, or no match, so
   move.l    a0,d1               ; PTR to name in d1
   bsr       _CheckExists        ; try for Lock on file
   tst.l     d0
   beq       OverWrite           ; Is new file, no problem
   move.l    d0,d1               ; old file, we'll unlock it now
   DosCall   UnLock              ; then check on user's wishes...

FExists
   TxtReq    FExistsMsg(pc),CancelTxt(pc),AppendTxt(pc),OverWriteTxt(pc)
   tst.l     d0
   beq       CancelPRT
   cmpi      #1,d0
   beq.s     Append
   bra.s     OverWrite
FExistsMsg
   dc.b      10,' Chosen file already exists ',10,10,' What should I do now? ',10,0
   EvenPC

Append
   lea       PathName(a5),a0
   move.l    a0,d1
   move.l    #MODE_READWRITE,d2  ; to allow append mode
   DosCall   Open
   tst.l     d0                  ; see if a handle was returned (success)
   beq       PRTError            ; No? Skip the rest
   move.l    d0,PRTFile(a5)      ; or store handle if successful
   move.l    d0,d1               ; and put in d1 with
   Zero      d2                  ; no offset in d2
   moveq     #1,d3               ; and OFFSET_END in d3 for a call to
   DosCall   Seek                ; Seek to end of file (where we add on!)
   bra.s     PrintIt             ; ready to print...

OverWrite
   lea       PathName(a5),a0     ; get PTR to user input
   move.l    a0,d1               ; into d1 as PTR to name
   move.l    #MODE_NEWFILE,d2    ; overwrite mode
   DosCall   Open                ; and open it up
   tst.l     d0                  ; check for returned handle
   beq       PRTError            ; no - get out
   move.l    d0,PRTFile(a5)      ; store it for close down

PrintIt
   move.l    a2,PageBot(a5)      ; just hiding it
   cmpi.b    #1,PrtScFlag(a5)    ; was it a PrtSc only?
   beq.s     PrtScIt             ; handle it differently
   DosPrt    PRTFile(a5),FileMemBuf(a5),FileSize(a5)
   cmpi.l    #-1,d0              ; oops! not all chars written..
   beq.s     PRTError
   bra.s     PRTCleanUp

PrtScIt
   move.l    PageTop(a5),d2      ; top of page, & ptr to file
   move.l    a2,d3               ; page bottom into d3
   sub.l     d2,d3               ; difference is chars to write
   move.l    PRTFile(a5),d1      ; "file" ptr into d1
   DosCall   Write               ; pump it out
   cmpi.l    #-1,d0              ; not all written?
   beq.s     PRTError            ; oops!
   move.b    #0,PrtScFlag(a5)    ; done with PrtScrn

PRTCleanUp
   move.l    PRTFile(a5),d1      ; IF is PTR, THEN
   beq.s     DonePRT
   DosCall   Close               ; close file
   move.l    #0,PRTFile(a5)      ; and clear storage!
DonePRT
   moveq     #Again,d0           ; Redisplay from where we were
   PullReg   d2-d7
   rts

CancelPRT
   cmpi.b    #1,PrtScFlag(a5)    ; if was PrtScreen operation
   bne.s     1$
   move.b    #0,PrtScFlag(a5)    ; cancel THAT too! :-)
1$
   bra       PRTCleanUp

PRTError
   TxtReq    PRTErrorMsg(pc),ResumeTxt(pc)
   bra       CancelPRT   
PRTErrorMsg
   dc.b      10,' ERROR occurred! ',10,0
   EvenPC

ChkDev
   lea       PathName(a5),a0     ; load PTR to user input
   lea       PRTName(pc),a1      ; and possible value
   bsr.s     _CompChar           ; and compare
   tst.l     d0                  ; if match, d0 = last char
   bne.s     MatchFound          ; if zero, then keep checking
   lea       PathName(a5),a0
   lea       PARName(pc),a1      ; next poss to check
   bsr.s     _CompChar
   tst.l     d0
   bne.s     MatchFound          ; keep checking if zero
   lea       PathName(a5),a0
   lea       SERName(pc),a1
   bsr.s     _CompChar
MatchFound
   rts                           ; either way - d0 = success in matching :-)

_CompChar
   move.l    #3,d4               ; countdown of chars for DBRA
   Zero      d0                  ; clear out d0
CompLoop
   move.b    (a0)+,d0            ; move char into d0
   bsr       _ConvChar           ; and get char converted (if needed)
   move.b    (a1)+,d5            ; compare w/char at current posn in name
   cmp.b     d5,d0               ; does it match char in d0?
   beq.s     CompMore            ; if match, continue check
   cmp.b     d5,d1               ; does it match char in d1?
   beq.s     CompMore            ; if match continue check
   bra.s     CompNot             ; otherwise get out
CompMore
   dbra      d4,CompLoop         ; was match: chars left?
   rts
CompNot
   Zero      d0
   rts

***   Search Operations  ***
* we give up speed for space here and use the same search 
* whether or not case sensitive.  2 compares for every 
* character, but a 680x0 is pretty quick, right?

SRCH
   PushReg   d3-d7               ; save 'em for later!
   move.b    #0,SrchType(a5)     ; we are case sensitive!
   lea       SrchSensTitle(pc),a1
   bra.s     Search
SrchSensTitle
   dc.b      ' Case Sensitive Search ',0
   EvenPC

SRCHI
   PushReg   d3-d7               ; save 'em for later
   move.b    #1,SrchType(a5)     ; we are NOT case sensitive!
   lea       SrchInsensTitle(pc),a1
   bra.s     Search
SrchInsensTitle
   dc.b      ' Case insensitive Search ',0
   EvenPC

Search
   lea       KeyBuff(a5),a0      ; load buffer
   move.b    #0,(a0)
   lea       GetString(a5),a0    ; load structure
   move.l    a1,gs_titlebar(a0)
   lea       KeyBuff(a5),a1
   move.l    a1,gs_stringbuffer(a0)
   move.w    #80,gs_stringsize(a0)
   move.w    #40,gs_visiblesize(a0)
   ReqCall   NewGetString        ; call requester for string
   tst.l     d0
   beq       NoMatch
   lea       KeyBuff(a5),a0
   Zero      d0
LenGetLoop
   addq      #1,d0
   tst.b     (a0)+
   bne.s     LenGetLoop   
   move.l    d0,d3               ; store length of string in d3
   subq.l    #1,d3               ; less one (for dbra)
   move.l    d3,d4               ; and in d4 for testing
   move.l    a2,CurPosn(a5)      ; in case we need to know!
   PushReg   d3                  ; because BackOnePage needs it
   bsr       _BackOnePage        ; to start of displayable page
   PullReg   d3                  ; and back to our value
   bra.s     StartSrch           ; and start search

ReSearch 
   PushReg   d3-d7               ; save 'em for later
   move.l    SrchOK(a5),d3       ; check if previous valid search
   beq.s     NoMatch             ; no? skip outta here!
   move.l    d3,d4               ; Yes, copy string length(-1) to d4
   move.l    a2,CurPosn(a5)      ; in case we need to know!
   move.l    LastPosn(a5),a2     ; "stored" from last search

StartSrch 
FirstChar 
   Zero      d0                  ; clear out d0
   lea       KeyBuff(a5),a0      ; PTR to string in a0
   move.b    (a0)+,d0            ; move first char into d0
   bsr       _ConvChar           ; and get char converted (if needed)
SrchLoop 
   move.b    (a2)+,d5            ; compare w/char at current posn in file
   cmp.b     d5,d0               ; does it match char in d0?
   beq.s     Match1              ; if match, continue check
   cmp.b     d5,d1               ; does it match char in d1?
   beq.s     Match1              ; if match continue check
   cmpa.l    a2,a3               ; see if past EOF
   ble.s     NoMatch             ; if we are, then no match, natch
   bra       SrchLoop            ; no match yet, so keep searching

Match1 
   move.l    a2,d7               ; store new position in file
MatchLoop
   subq.l    #1,d4               ; lower string count by 1
   beq.s     Matched             ; if none left, match is good
   move.b    (a0)+,d0            ; get next char of string
   bsr       _ConvChar           ; and set it up for checking
   cmpa.l    a2,a3               ; check against EOF count
   ble.s     NoMatch             ; at EOF - stop already!
   move.b    (a2)+,d5            ; compare w/char at current posn in file
   cmp.b     d5,d0               ; does it match char in d0?
   beq       MatchLoop           ; if match, continue check
   cmp.b     d5,d1               ; does it match char in d1?
   beq       MatchLoop           ; if match continue check
   move.l    d3,d4               ; otherwise reset string length check
   move.l    d7,a2               ; set a2 back to last unchecked position
   bra       FirstChar           ; and start search for first char again
Matched
   move.b    #0,TopFlag(a5)
   move.l    d7,LastPosn(a5)     ; "store" location to display from
   move.l    LastPosn(a5),CurPosn(a5)  ; for reasonable value if "re-search" fails
   PushReg   d2-d4
   bsr       _PrevLine           ; set a2 to start of line found
   PullReg   d2-d4
   moveq     #PageDown,d0        ; tell display routine to go from here
   move.l    d3,SrchOK(a5)       ; Set flag (w num of chars in string
   PullReg   d3-d7               ; and reset d3-d7 as before
   rts

NoMatch
   move.l    CurPosn(a5),a2      ; and current posn in file!
   move.l    #0,SrchOK(a5)       ; Set flag that search DIDN'T work
   TxtReqCt  NotFoundMsg(pc),ResumeTxt(pc),KeyBuff(a5)
   PullReg   d3-d7               ; return d3/d7 to previous contents
   moveq     #Again,d0           ; redisplay from where we were
   rts
NotFoundMsg
   dc.b      10,' <%s> ',10,10,'  Not Found  ',10,0
   EvenPC

_ConvChar
   move.l    d0,d1               ; copy it into d1
   cmpi.b    #0,SrchType(a5)     ; is case sensitive search?
   beq.s     NotAlpha            ; do nothing else :-)
   cmpi.b    #'A',d0             ; is char upper case?
   blt.s     NotAlpha            ; lower, not alphabetic
   cmpi.b    #'Z',d0             ;
   ble.s     UpperCase           ; lower or eq, is UpperCase Alpha
   cmpi.b    #'a',d0             ;
   blt.s     NotAlpha            ; lower, not alphabetic
   cmpi.b    #'z',d0             ;
   ble.s     LowerCase           ; lower or eq, is LowerCase Alpha
   bra.s     NotAlpha            ; higher, not alphabetic
UpperCase
   add.l     #32,d1              ; make d1 a lower case copy
   bra.s     NotAlpha            ; and get on with it
LowerCase
   sub.l     #32,d1              ; make d1 an upper case copy
NotAlpha
   rts

***  GOTO Percent of File  ***

GOTO
   lea       GetLong(a5),a0
   lea       GotoTitle(pc),a1
   move.l    a1,gl_titlebar(a0)
   move.l    #0,gl_defaultval(a0)
   move.l    #0,gl_minlimit(a0)
   move.l    #100,gl_maxlimit(a0)
   or.l      #GLNODEFAULTM,gl_flags(a0)  ; don't GIVE a default value
   ReqCall   GetLong
   tst.l     d0
   beq.s     GotoExit
   lea       GetLong(a5),a0
   move.l    gl_result(a0),d0
   tst.b     d0                  ; and got what back?
   beq.s     MeansTop            ; zero? hope user MEANT top :-)
   cmpi.b    #100,d0             ; was it 100?
   beq.s     MeansBottom         ; must mean go to bottom
   addq      #1,d0               ; kludge for rounding errors
   mulu      HunFileSize(a5),d0  ; multiply by 1/100 of the file's size
   move.l    FileMemBuf(a5),d1   ; start of file in d0
   add.l     d0,d1               ; add it to result of calc
   move.l    d1,a2               ; now we have PTR to display from
   move.b    #0,TopFlag(a5)      ; and we're NOT at top of file
   bsr       _PrevLine           ; back up to beginning of line
   move.l    a2,PageTop(a5)      ; mark this as top of page
GotoExit
   moveq     #PageUp,d0          ; tell main loop to show TO here
   rts
MeansBottom
   moveq     #Bottom,d0
   rts
MeansTop
   moveq     #Top,d0
   rts
GotoTitle
   dc.b      ' GO TO % ? ',0
   EvenPC

***  Useful General Subroutines  ***

_WrChar                          ; Enter with char to print in d0
   PushAll                       ; Save regs
   lea       CBuff(a5),a1        ; PTR to buffer in a1
   move.b    d0,(a1)             ; Put character in buffer
   DosPrt    RawHnd(a5),CBuff(a5),#1    ; and write it
   PullAll                       ; Restore regs
   rts
   
_ASCIIConv                       ; Enter with value for conversion in d1
                                 ; and buffer to store result in a0
   Zero      d0                  ; this routine only handles 4 decimal chars
   bsr.s     Do_It               ; because I want it to :-)  (for punching
   rts                           ; values into strings like RawName)
Do_It
   divu      #1000,d1            ; get 1000's digit
   bsr.s     Eval                ; evaluate and move remainder
   divu      #100,d1             ; get 100's digit
   bsr.s     Eval                ; 
   divu      #10,d1              ; get 10's digit
   bsr.s     Eval                ; 
   addq.l    #1,d0               ; if only character, we display the 0
Eval
   add       #48,d1              ; convert to ASCII value
   cmpi.b    #'0',d1             ; is it a leading ASCII Zero char now?
   bne.s     NotLdZero
   tst.l     d0                  ; test d0 for a previous no-zero char
   bne.s     NotLdZero           ; if was one, skip the change to space
   move.b    #' ',(a0)+          ; there wasn't - so store space instead
   bra.s     SetForNext          ; and get ready for next digit
NotLdZero
   addq.l    #1,d0               ; set flag that nonleadZero char preceded this
   move.b    d1,(a0)+            ; store digit
SetForNext
   clr.w     d1                  ; erase lower word
   swap      d1                  ; move remainder into lower word
   rts                           ; return for more (or to caller if done)

_ASCII2Val                       ; Enter with ASCII string PTR in a0
                                 ; returns with value in d1   
   Zero      d1                  ; clear it out
   bsr.s     DecLoop
   rts
DecLoop
   bsr.s     GetDigit            ; get converted digit
   blt.s     DecDone             ; less than ASCII 0, not digit (done?)
   cmpi.b    #9,d0               ; test if greater than 9
   bgt.s     DecDone             ; yes? get out 
   mulu.w    #10,d1              ; step up previous result by 10
   add       d0,d1               ; and add in the new digit
   bra.s     DecLoop             ; and back for more
DecDone
   rts
GetDigit
   Zero      d0
   move.b    (a0)+,d0            ; get digit, point to next...
   sub.b     #48,d0              ; 48 is ASCII value of 0 
   rts                           ; back to work
                      
*** Data Storage areas ***

RawName1
   dc.b      'raw:0/0        /'
   dc.b      'File:                          CTYPE 2.02         <HELP> for help    ',0
PosPrompt1
   dc.b      $9b,'  ;1H',$9b,'7m      % of '
   dc.b      '     KBytes   MODE = N   Click or <SPACE> = more ',$9b,'0m',$9b,'K',0
SPosPrompt1
   dc.b      $9b,'  ;1H ',$9b,'7m -MORE- ',$9b,'0m',$9b,'K',0
PRTName
   dc.b      'PRT:',0
PARName
   dc.b      'PAR:',0
SERName
   dc.b      'SER:',0
EditName
   dc.b      'ENV:Editor',0
ReqTitle
   dc.b      ' CType 2.02     Choose a File:   ',0
ClrLn
   dc.b      $9b,'M',$9b,'F',$9b,'E',0
CursorOn
   dc.b      $9b,$20,$70,0
CursorOff
   dc.b      $9b,$30,$20,$70,$F,0
GetWinStat
   dc.b      $9b,$30,$20,$71,0
SetMouse
   dc.b      $9b,'2;12{',0
YesTxt
   dc.b      ' Yes ',0
NoTxt
   dc.b      ' NO ',0
CancelTxt
   dc.b      ' Cancel ',0
AppendTxt
   dc.b      ' Append ',0
OverWriteTxt
   dc.b      ' OverWrite ',0
ResumeTxt
   dc.b      ' Resume ',0
HelpMsg
   dc.b      10,' Result               Command      Alternates     Num Pad',10,10
   dc.b      ' Forward a PAGE       SPACE        SHIFT-DOWN     PGDN       3 ',10
   dc.b      ' Forward a LINE       RETURN       DOWN           DOWN       2 ',10
   dc.b      ' Backward  PAGE       BACKSPACE    SHIFT-UP       PGUP       9 ',10
   dc.b      ' Backward  LINE       DELETE       UP             UP         8 ',10
   dc.b      ' TOP of file          <            LEFT           HOME       7 ',10
   dc.b      ' BOTTOM of file       >            RIGHT          END        1 ',10
   dc.b      ' Scroll RIGHT         RIGHT        R              RIGHT      6 ',10
   dc.b      ' Scroll LEFT          LEFT         L              LEFT       4 ',10
   dc.b      ' QUIT/Next File       ESC          Q              F10',10,10
   dc.b      '                      More HELP? ',10,0
HelpMsg2
   dc.b      10,' Result               Command      Alternates ',10,10
   dc.b      ' Change TAB Size      TAB                     (Default is 8)',10
   dc.b      ' Toggle FORMAT mode   F                       (Word Wrap)',10
   dc.b      ' Search for String    /                       (Case Sensitive)',10
   dc.b      ' Search for String    .                       (NOT Case sensitive) ',10
   dc.b      ' Next Occurrence      N                       (Of previous String)',10
   dc.b      ' Move N% into file    %N                      (where N = number)',10
   dc.b      ' Call your Editor     E                       (Def in ENV:Editor)',10
   dc.b      ' Print complete file  P            SHIFT-F7   (for WP users!)',10
   dc.b      ' Print screen only    PrtSc        F7         (or ANY * key)',10,10
   dc.b      ' UNCONDITIONAL EXIT   CTRL-C',10,10
   dc.b      '                      More HELP? ',10,0
   EvenPC

   end                           ; yup - that's IT!
