; s.Tracker
;

                GET             <Asm$LibRoot>regs
                GET             <Asm$LibRoot>swis
                GET             <Asm$LibRoot>vectors
                GET             <Asm$LibRoot>general
                GET             <Asm$LibRoot>services
                GET             <Asm$LibRoot>Date

                GET             s.Wimp

SWIChunk        *               &CF000
;                 ^               SWIChunk
; Tracker_Open    #               1
; Tracker_Close   #               1
; Tracker_SetPos  #               1
; Tracker_WriteS  #               1
; Tracker_CLS     #               1
; Tracker_Simple  #               1

                MACRO
$label          PACK            $size, $word
                ASSERT          :LEN: "$word" <= $size
$label          =               "$word"
                %               $size - :LEN: "$word"
                MEND

ws              RN              12

                ^               0, ws

Byte            *               1
Word            *               4
StackSize       *               1024
TempSize        *               512

MyTask          #               Word
Windows         #               Word
ActiveMenu      #               Word
NextHandle      #               Word
NextOpen        #               Word
SimpleHandle    #               Word
progInfo        #               Word
SaveAs          #               Word
SaveAsName      #               Word        ; Points to the text buffer
Message         #               256
TempWorks       #               TempSize
MenuWork        #               (7 + 3 * 6) * Word
OutWindow       #               4
OutDefn         #               88
Stack           #               StackSize

WSSize          *               :INDEX: {VAR}

; Structure which exists at the head of each active window

TitleLen        *               64

                ^               0
Handle          #               Word
Link            #               Word
Flags           #               Word
Scrolled        #               Word
Offset          #               Word
MaxX            #               Word
MaxY            #               Word
CurX            #               Word
CurY            #               Word
ChBox           #               Word * 4
DispOffset      #               Word
WHandle         #               Word
WTitle          #               TitleLen

WHeaderSize     *               :INDEX: {VAR}

; Window flags

AutoNewLine     *               1 :SHL:  0
IsOpen          *               1 :SHL: 16
BeenClosed      *               1 :SHL: 17
AutoGot         *               1 :SHL: 18
AutoIsCR        *               1 :SHL: 19

; Data follows here

PollMask        *               2_00000000000000000001100000110000

; Start of code

ModuleBase      B               Main
                &               Initialise      - ModuleBase
                &               Finalise        - ModuleBase
                &               Service         - ModuleBase
                &               Title           - ModuleBase
                &               Help            - ModuleBase
                &               Commands        - ModuleBase
                &               SWIChunk
                &               SWIHandler      - ModuleBase
                &               SWITable        - ModuleBase
                &               0

Title           =               "Tracker", 0

Help            =               "Tracker", 9, 9, "1.00", " ($MakeDate)", 0
                ALIGN

Initialise      STMFD           sp!, {lr}
                LDR             r2, [ws]
                TEQ             r2, #0
                BNE             Init1
                MOV             r0, #6
                LDR             r3, = WSSize
                SWIX            OS_Module
                LDMVSFD         sp!, {pc}
                STR             r2, [ws]
Init1           MOV             ws, r2
                MOV             r0, #0
                STR             r0, MyTask
                STR             r0, Windows
                STR             r0, NextHandle
                STR             r0, NextOpen
                STR             r0, SimpleHandle
                BL              MakeFS
                LDMFD           sp!, {pc}

Finalise        TEQ             r10, #0
                MOVEQS          pc, lr

                LDR             r2, [ws]
                LDR             r0, [r2, #:INDEX: MyTask]
                TEQ             r0, #0
                ADRNE           r0, TaskActive
                ORRNES          pc, lr, #V_bit

                STMFD           sp!, {lr}

                BL              RemoveFS

                MOV             r0, #0
                STR             r0, [ws]

                LDR             r3, [r2, #:INDEX: Windows]
Finalise1       MOV             r0, #7
                SWIX            OS_Module
                BLVC            RMAShrink
                MOVS            r2, r3
                LDRNE           r3, [r2, #Link]
                BNE             Finalise1

                LDMFD           sp!, {pc}^

Service         TEQ             r1, #Service_Reset
                TEQNE           r1, #Service_StartedWimp
                MOVNES          pc, lr

                STMFD           sp!, {lr}
                LDR             ws, [ws]
                MOV             lr, #0
                STR             lr, MyTask
                LDMFD           sp!, {pc}^

Commands        =               "Tracker_Start", 0
                ALIGN
                &               TrackerStart - ModuleBase
                =               0, 0, 0, 0
                &               TS_Syntax    - ModuleBase
                &               TS_Help      - ModuleBase
                =               0
                ALIGN

TS_Help         =               "*", 27, 0, " starts or restarts", 27, 2, "Tra"
                =               "cker task.  Any trace windows which are open "
                =               "will be preserved.", 13
TS_Syntax       =               27, 1, 0
                ALIGN

TrackerStart    LDR             ws, [ws]
                LDR             r0, MyTask
                TEQ             r0, #0
                ADRNE           r0, TaskActive
                ORRNES          pc, lr, #V_bit

                STMFD           sp!, {lr}
                MOV             r0, #2
                ADR             r1, Title
                SWIX            OS_Module
                LDMFD           sp!, {pc}

NonFatal        LDR             r1, = 2_00000011
                ADR             r2, Title
                SWIX            Wimp_ReportError
                TEQ             r1, #2
                BEQ             ExitTask
                B               MainLoop

Fatal           LDR             r1, = 2_00000010
                ADR             r2, Title
                SWIX            Wimp_ReportError
                B               ExitTask

TaskActive      ERROR           &100, "Tracker is active"

Main            LDR             ws, [ws]
                LDR             r0, MyTask
                LDR             r1, TASK
                TEQ             r0, #0
                SWIX            Wimp_CloseDown, NE

                MOV             r0, #200
                ADR             r2, Title
                SWIX            Wimp_Initialise
                MOVVSS          pc, lr

                STR             r1, MyTask
                ADRL            sp, Stack + StackSize

                BL              LoadTemplates
                BL              BarIcon

; Mark any windows as needing to be opened

                LDR             r2, Windows
Main1           TEQ             r2, #0
                BEQ             MainLoop
                MOV             r0, #-1
                STR             r0, [r2, #WHandle]
                LDR             r2, [r2, #Link]
                B               Main1

MainLoop        ADRL            sp, Stack + StackSize

                SWIX            OS_ReadMonotonicTime
                ADD             r2, r0, #5
                LDR             r0, = PollMask
                ADR             r1, Message
                SWIX            Wimp_PollIdle

                TEQ             r0, #Null_Reason_Code
                BEQ             Background
                TEQ             r0, #Redraw_Window_Request
                BEQ             RedrawWind
                TEQ             r0, #Open_Window_Request
                BEQ             OpenWind
                TEQ             r0, #Close_Window_Request
                BEQ             CloseWind
                TEQ             r0, #Mouse_Click
                BEQ             Clicked
                TEQ             r0, #User_Drag_Box
                BEQ             DragEnded
                TEQ             r0, #Key_Pressed
                BEQ             KeyPressed
                TEQ             r0, #Menu_Selection
                BEQ             DecodeMenu
                TEQ             r0, #User_Message
                TEQNE           r0, #User_Message_Recorded
                BEQ             GotMessage

                B               MainLoop

                LTORG

TASK            =               "TASK"

OpenWind        ADR             r1, Message
                SWIX            Wimp_OpenWindow
                BVS             NonFatal
                B               MainLoop


RUSure          &               1
                =               "This Tracker window is still open.  Only "
                =               "click OK if you are sure you want to "
                =               "close it."

CloseWind       BL              FindWind
                TEQ             r2, #0
                BEQ             CloseW2
                LDR             r0, [r2, #Flags]
                TST             r0, #IsOpen
                BEQ             CloseW1
                MOV             r4, r2
                ADR             r0, RUSure
                MOV             r1, #2_00000111
                ADR             r2, Title
                SWIX            Wimp_ReportError
                MOV             r2, r4
                TEQ             r1, #1
                BNE             MainLoop

CloseW1         LDR             r0, SimpleHandle
                LDR             r1, [r2, #Handle]
                TEQ             r0, r1
                MOVEQ           r0, #0
                STREQ           r0, SimpleHandle

                LDR             r0, [r2, #Link]
                TEQ             r3, #0
                STREQ           r0, Windows
                STRNE           r0, [r3, #Link]
                MOV             r0, #7
                SWIX            OS_Module
                BLVC            RMAShrink
                BVS             NonFatal

                ADR             r1, Message
                SWIX            Wimp_DeleteWindow
                BVS             NonFatal
                B               MainLoop

CloseW2         ADR             r1, Message
                SWIX            Wimp_CloseWindow
                BVS             NonFatal
                B               MainLoop

                ^               0
IconMenuInfo    #               1
IconMenuQuit    #               1

DecodeMenu      LDR             r0, ActiveMenu
                TEQ             r0, #0
                BNE             DecodeM1
                LDR             r0, Message
                TEQ             r0, #IconMenuQuit
                BEQ             ExitTask
                B               MainLoop

; Handle window menu

DecodeM1        B               MainLoop

Clicked         LDR             r0, Message + 8
                TST             r0, #2_010
                BEQ             OtherClick

                LDR             r0, Message + 12
                CMP             r0, #-2
                BNE             WindowMenu

; Icon bar menu

                MOV             r0, #0
                STR             r0, ActiveMenu

                ADR             r0, MenuWork
                ADR             r1, IconMenuDef
                LDR             r2, Message
                SUBS            r2, r2, #64
                MOV             r3, #46 * 4
                BL              MakeMenu
                B               MainLoop

                ^               0
SaveAsFileName  #               1
SaveAsFileIcon  #               1
SaveAsOK        #               1

IconMenuDef     MENU            "Tracker", 16 * 5
                ENTRY           0, :INDEX: progInfo, "Info"
                ENTRY           1 :SHL: 7, -1, "Quit"

WindowMenu      LDR             r0, Message + 12
                BL              FindWindow
                TEQ             r2, #0
                BEQ             MainLoop
                STR             r2, ActiveMenu

                ADR             r0, MenuWork
                ADR             r1, WindMenuDef
                LDR             r2, Message
                LDR             r3, Message + 4
                SUB             r2, r2, #56

                BL              MakeMenu

; Fill the filename icon in the saveas window with the text 'TrackFile'

                ADR             r0, TrackFile
                LDR             r1, SaveAsName
WindowM1        LDRB            r2, [r0], #1
                STRB            r2, [r1], #1
                TEQ             r2, #0
                BNE             WindowM1
                B               MainLoop

TrackFile       =               "TrackFile", 0
                ALIGN

WindMenuDef     MENU            "Tracker", 16 * 5
                ENTRY           0, :INDEX: progInfo, "Info"
                ENTRY           1 :SHL: 7, :INDEX: SaveAs, "Save"

; Make a menu, args r1-r3 as for Wimp_CreateMenu, r0 is the place to keep
; it.  Submenu field points to a word in workspace which contains the actual
; contents for the submenu.

MakeMenu        STMFD           sp!, {r0-r1, r4-r10, lr}

                LDMIA           r1!, {r4-r10}
                STMIA           r0!, {r4-r10}

MakeMenu1       LDMIA           r1!, {r4-r9}
                CMP             r5, #-1
                LDRNE           r5, [ws, r5]
                STMIA           r0!, {r4-r9}
                TST             r4, #1 :SHL: 7
                BEQ             MakeMenu1

                LDR             r1, [sp]
                SWIX            Wimp_CreateMenu
                BVS             NonFatal
                LDMFD           sp!, {r0-r1, r4-r10, pc}

; Handle Select or Adjust clicks.  The one which interests us at the moment
; is drag on the SaveAs file icon.

OtherClick      TST             r0, #2_100 :SHL: 4
                BEQ             OtherC1

; Got it, so start dragging, and leave the rest to someone else.  When the
; dragging ends we may assume that the window to be saved is the window
; where the last menu sprouted.

                ADR             r1, Stack
                LDR             r0, SaveAs
                STR             r0, [r1, #0]
                SWIX            Wimp_GetWindowState
                BVS             NonFatal

                LDMIB           r1, {r2-r7}

                MOV             r0, #SaveAsFileIcon
                STR             r0, [r1, #4]
                SWIX            Wimp_GetIconState
                BVS             NonFatal

; Now convert the icon's outline to screen coordinates

                ADD             r0, r1, #8
                LDMIA           r0, {r8-r11}
                SUB             r2, r2, r6
                SUB             r5, r5, r7
                ADD             r8, r8, r2
                ADD             r9, r9, r5
                ADD             r10, r10, r2
                ADD             r11, r11, r5
                STMIA           r0, {r8-r11}

                SUB             sp, sp, #4 * Word
                STMFD           sp!, {r1}
                ADR             r0, ModeVars
                ADD             r1, sp, #Word
                SWIX            OS_ReadVduVariables
                LDMFD           sp!, {r1, r4-r7}
                MOV             r6, r6, LSL r4
                MOV             r7, r7, LSL r5
                MOV             r4, #0
                MOV             r5, #0
                ADD             r0, r1, #24
                STMIA           r0, {r4-r7}
                MOV             r0, #5
                STR             r0, [r1, #4]
                SWIX            Wimp_DragBox

                B               MainLoop

OtherC1         TST             r0, #2_101
                BEQ             MainLoop
                LDR             r1, SaveAs
                LDR             r0, Message + 12
                TEQ             r0, r1
                LDREQ           r0, Message + 16
                TEQEQ           r0, #SaveAsOK
                BNE             MainLoop
                B               DoSave

; Comes here when a user drag ends, currently assuming that we wish to save
; a file, so find out where the pointer is, and send a message to that
; window, saying we want to save our stuff.

DragEnded       ADR             r1, Stack
                SWIX            Wimp_GetPointerInfo
                ADR             r0, Message + 20        ; Data first

                LDR             r2, [r1, #12]
                LDR             r3, [r1, #16]
                LDR             r4, [r1, #0]
                LDR             r5, [r1, #4]
                MOV             r6, #0
                LDR             r7, =&FFF
                STMIA           r0!, {r2-r7}
                LDR             r3, SaveAsName
DragEnd1        LDRB            r4, [r3], #1
                CMP             r4, #" "
                MOVLO           r4, #0
                STRB            r4, [r0], #1
                BHS             DragEnd1

; Now setup message header

                ADR             r1, Message
                SUB             r0, r0, r1
                ADD             r0, r0, #3
                BIC             r0, r0, #3
                STR             r0, [r1, #MB_Length]
                MOV             r0, #0
                STR             r0, [r1, #MB_YourRef]
                MOV             r0, #Message_DataSave
                STR             r0, [r1, #MB_Action]

; R2 is window handle preserved from above

                MOV             r0, #User_Message
                SWIX            Wimp_SendMessage
                BVS             NonFatal

                B               MainLoop

                LTORG

; They want our file

DataSave        ADR             r1, Message + 44
                LDR             r2, ActiveMenu
                BL              SaveFile
                
                ADR             r1, Message
                LDR             r0, [r1, #MB_MyRef]
                STR             r0, [r1, #MB_YourRef]
                MOV             r0, #Message_DataLoad
                STR             r0, [r1, #MB_Action]
                
                LDR             r2, [r1, #MB_Me]
                MOV             r0, #User_Message
                SWIX            Wimp_SendMessage
                BVS             NonFatal
                MOV             r1, #-1
                SWIX            Wimp_CreateMenu
                B               MainLoop

FileError       STMFD           sp!, {r0}
                MOV             r0, #0
                SWIX            OS_Find
                LDMFD           sp!, {r0}
                B               NonFatal

; Handle a keypress

KeyPressed      LDR             r0, Message
                LDR             r1, Message + 4
                LDR             r2, Message + 24
                LDR             r3, SaveAs

                TEQ             r0, r3
                TEQEQ           r1, #SaveAsFileName
                TEQEQ           r2, #13
                BNE             MainLoop

; Return pressed, so try to save it

DoSave          LDR             r1, SaveAsName
                LDR             r2, ActiveMenu
                BL              SaveFile
                MOV             r1, #-1
                SWIX            Wimp_CreateMenu
                B               MainLoop

; Save a window at R2 into the file at R1, setting the file's type to text

SaveFile        STMFD           sp!, {r0-r10, lr}
                MOV             r0, #&83
                SWIX            OS_Find
                BVS             NonFatal
                MOV             r1, r0

; r9 is base of data, r10 is byte after end

                ADD             r9, r2, #WHeaderSize
                LDR             r3, [r2, #MaxY]
                LDR             r5, [r2, #MaxX]
                MLA             r10, r3, r5, r9
                LDR             r6, [r2, #Offset]
                MLA             r4, r5, r6, r9

                MOV             r5, #0           ; Newline counter
SaveF1          MOV             r6, #0           ; Space counter
                LDR             r7, [r2, #MaxX]

SaveF2          CMP             r4, r10
                SUBHS           r4, r4, r10
                ADDHS           r4, r4, r9

                LDRB            r8, [r4], #1
                TEQ             r8, #" "
                ADDEQ           r6, r6, #1
                BEQ             SaveF7

; Not a space, so flush newlines, spaces then this character

                TEQ             r5, #0
                BEQ             SaveF4
                MOV             r0, #10
SaveF3          SWIX            OS_BPut
                BVS             FileError
                SUBS            r5, r5, #1
                BNE             SaveF3

SaveF4          TEQ             r6, #0
                BEQ             SaveF6
                MOV             r0, #" "
SaveF5          SWIX            OS_BPut
                BVS             FileError
                SUBS            r6, r6, #1
                BNE             SaveF5

; Now the character!

SaveF6          MOV             r0, r8
                SWIX            OS_BPut
                BVS             FileError

SaveF7          SUBS            r7, r7, #1
                BNE             SaveF2
                ADD             r5, r5, #1
                SUBS            r3, r3, #1
                BNE             SaveF1

                MOV             r0, #0
                SWIX            OS_Find
                BVS             NonFatal

                MOV             r0, #18
                LDR             r1, [sp, #Word * 1]
                LDR             r2, = &FFF
                SWIX            OS_File
                BVS             NonFatal

                LDMFD           sp!, {r0-r10, pc}^

GotMessage      LDR             r0, Message + 16
                TEQ             r0, #Message_Quit
                BEQ             ExitTask
                TEQ             r0, #Message_DataSaveAck
                BEQ             DataSave
                BNE             MainLoop

; Handle quit message

ExitTask        LDR             r0, MyTask
                MOV             r1, #0
                STR             r1, MyTask
                LDR             r1, TASK
                SWIX            Wimp_CloseDown
                SWIX            OS_Exit

IconFlags       &               2_00000000000000000011000000011010
IconData        PACK            12, "!tracker"

BarIcon         STMFD           sp!, {r1-r8, lr}
                SUBS            sp, sp, #36     ; That's the size of it

; First find the icon's size

                MOV             r0, #40
                ADR             r2, IconData
                SWIX            Wimp_SpriteOp  ; width in r3, height in r4

                MOVVC           r0, r6
                MOVVC           r1, #4
                SWIX            OS_ReadModeVariable, VC
                MOVVC           r3, r3, LSL r2
                MOVVC           r1, #5
                SWIX            OS_ReadModeVariable, VC
                MOVVC           r4, r4, LSL r2
                ADRVC           r0, IconFlags
                LDMVCIA         r0, {r5-r8}
                MOVVC           r0, #-1
                MOVVC           r1, #0
                MOVVC           r2, #0
                STMVCIA         sp, {r0-r8}
                MOVVC           r1, sp
                SWIX            Wimp_CreateIcon, VC
                BVS             Fatal
                ADD             sp, sp, #36
                LDMFD           sp!, {r1-r8, pc}

Templates       =               "<Tracker$Dir>.Templates", 0
                ALIGN

Info            =               "progInfo", 0
Output          =               "Output", 0
Saver           =               "SaveAs", 0

TempNotFound    ERROR           &110, "Template not found"

TempError       STMFD           sp!, {r0}
                SWIX            Wimp_CloseTemplate
                LDMFD           sp!, {r0}
                B               Fatal

LoadTemplate    ADR             r6, Message
LoadTemp1       LDRB            r4, [r5], #1
                STRB            r4, [r6], #1
                TEQ             r4, #0
                BNE             LoadTemp1
                MOV             r4, #-1
                ADR             r5, Message
                MOV             r6, #0
                SWIX            Wimp_LoadTemplate
                BVS             TempError
                TEQ             r6, #0
                ADREQ           r0, TempNotFound
                BEQ             TempError
                MOVS            pc, lr

TemplateWindow  STMFD           sp!, {lr}
                ADR             r1, Stack
                BL              LoadTemplate
                SWIX            Wimp_CreateWindow
                BVS             TempError
                LDMFD           sp!, {pc}^

LoadTemplates   STMFD           sp!, {r0-r6, lr}
                ADR             r1, Templates
                SWIX            Wimp_OpenTemplate
                BVS             Fatal

                ADR             r2, TempWorks
                ADD             r3, r2, #TempSize
                ADR             r5, Info
                BL              TemplateWindow
                STR             r0, progInfo

                ADR             r5, Saver
                BL              TemplateWindow
                STR             r0, SaveAs

; Get address of SaveAs name field, assuming the window definition is still
; in place at the bottom of the stack, and R1 still points to it.

                LDR             r0, [r1, #88 + SaveAsFileName * 32 + 20]
                STR             r0, SaveAsName

                ADR             r1, OutDefn
                ADR             r5, Output
                BL              LoadTemplate

LoadTempDone    SWIX            Wimp_CloseTemplate
                BVS             Fatal
                LDMFD           sp!, {r0-r6, pc}^

; Offsets into OutDefn

WorkBack        *               35
ExX0            *               40
ExY0            *               44
ExX1            *               48
ExY1            *               52
TitleFlags      *               56
TitleData       *               72

; Offsets into OutWindow (which overlaps OutDefn)

BoxX0           *                4
BoxY0           *                8
BoxX1           *               12
BoxY1           *               16
ScrX            *               20
ScrY            *               24
OpenBehind      *               28

ModeVars        &               4, 5, 11, 12, -1

; Open a window for the first time

FirstOpen       STMFD           sp!, {r0-r8, lr}

; First get the screen size

                SUB             sp, sp, #4 * Word
                STMFD           sp!, {r1}
                ADR             r0, ModeVars
                ADD             r1, sp, #Word
                SWIX            OS_ReadVduVariables
                LDMFD           sp!, {r1, r4-r7}
                MOV             r6, r6, LSL r4
                MOV             r7, r7, LSL r5

; Now get window's extent

                ADD             lr, r1, #ExX0 + 4
                LDMIA           lr, {r2-r5}          ; Get extent

; X position

                SUB             r4, r4, r2
                MOV             r4, r4, LSR #1
                CMP             r4, r6, LSR #2
                MOVGE           r4, r6, LSR #2
                RSB             r2, r4, #0
                ADD             r2, r2, r6, LSR #1
                ADD             r4, r4, r6, LSR #1

; Y position

                SUB             r3, r3, r5
                MOV             r5, #0
                CMN             r3, r7, LSR #1
                MVNLS           r3, r7, LSR #1     ; Near enough

                LDR             r6, NextOpen
                ADD             lr, r3, r6
                CMPS            lr, #64
                SUBLT           r6, r7, #96

                ADD             r3, r3, r6
                ADD             r5, r5, r6
                SUB             r6, r6, #48
                STR             r6, NextOpen

                MOV             r6, #0
                MOV             r7, #0
                MOV             r8, #-1
                ADD             lr, r1, #BoxX0
                STMIA           lr, {r2-r8}
                SWIX            Wimp_OpenWindow
                LDMFD           sp!, {r0-r8, pc}

TopMargin       *               8
LeftMargin      *               8
 
; Regular background activity: scans list of windows, any which have whandle
; == -1, open a window for them.  If any windows have a non null changed box
; do redraws on them.

Background      LDR             r2, Windows
Backg1          TEQ             r2, #0
                BEQ             MainLoop
                LDR             r0, [r2, #WHandle]
                CMP             r0, #-1
                BNE             Backg2

; Create and open a new window

                ADR             r1, OutDefn

; Set window size

                MOV             r0, #&FF
                STRB            r0, [r1, #WorkBack]
                MOV             r0, #0
                STR             r0, [r1, #ExX0]
                STR             r0, [r1, #ExY1]
                LDR             r0, [r2, #MaxX]
                MOV             r0, r0, LSL #4
                ADD             r0, r0, #LeftMargin * 2
                STR             r0, [r1, #ExX1]
                LDR             r0, [r2, #MaxY]
                MOV             r0, r0, LSL #5
                ADD             r0, r0, #TopMargin * 2
                RSB             r0, r0, #0
                STR             r0, [r1, #ExY0]

                LDR             r0, [r1, #TitleFlags]
                ORR             r0, r0, #1 :SHL: 8
                STR             r0, [r1, #TitleFlags]
                ADD             r0, r2, #WTitle
                STR             r0, [r1, #TitleData]
                MOV             r0, #TitleLen
                STR             r0, [r1, #TitleData + 8]
                SWIX            Wimp_CreateWindow
                BVS             NonFatal
                STR             r0, [r2, #WHandle]

; Now open it

                ADR             r1, OutWindow
                STR             r0, [r1]
                BL              FirstOpen
                BVS             NonFatal

Backg2          LDR             r0, [r2, #ChBox]
                CMP             r0, #-1
                BLNE            UpdateWind

                LDR             r0, [r2, #Flags]
                TST             r0, #BeenClosed
                BICNE           r0, r0, #BeenClosed
                STRNE           r0, [r2, #Flags]
                BLNE            UpdateAll

                LDR             r2, [r2, #Link]
                B               Backg1

; Find the window to which the message at Message is directed to

FindWind        LDR             r0, Message
FindWindow      LDR             r2, Windows
                MOV             r3, #0
FindWind1       TEQ             r2, #0
                LDRNE           r1, [r2, #WHandle]
                TEQNE           r0, r1
                MOVEQS          pc, lr
                MOV             r3, r2
                LDR             r2, [r2, #Link]
                B               FindWind1

; Handle a window redraw

RedrawWind      BL              FindWind
                TEQ             r2, #0
                BEQ             MainLoop

                ADR             r1, Stack
                STR             r0, [r1]
                SWIX            Wimp_RedrawWindow
                BVS             MainLoop             ; Don't report errors

RedrawW1        TEQ             r0, #0
                BEQ             MainLoop

                BL              DrawBit

                SWIX            Wimp_GetRectangle
                BVS             MainLoop
                B               RedrawW1

; Update the entire visible area of a window

UpdateAll       STMFD           sp!, {r3-r8, lr}

                ADR             r1, Stack
                LDR             r0, [r2, #WHandle]
                STR             r0, [r1]

                SWIX            Wimp_GetWindowState
                LDMIB           r1, {r3-r8}
                SUB             r4, r4, r6
                SUB             r5, r5, r3
                MOV             r3, r7
                MOV             r6, r8
                ADD             r4, r4, r8
                ADD             r5, r5, r7
                STMIB           r1, {r3-r6}

                ADD             lr, r2, #ChBox
                MOV             r3, #-1
                MOV             r4, #-1
                MOV             r5, #-1
                MOV             r6, #-1
                STMIA           lr, {r3-r6}

                SWIX            Wimp_UpdateWindow
                LDMVSFD         sp!, {r3-r8, pc}

UpdateA1        TEQ             r0, #0
                LDMEQFD         sp!, {r3-r8, pc}^

                BL              DrawBit

                SWIX            Wimp_GetRectangle
                B               UpdateA1

; Convert a window's changed box into a suitable rectangular area then go
; through an update loop.  Note that this is a subroutine whereas RedrawWind
; is directly linked into the polling loop.

UpdateWind      STMFD           sp!, {r3-r7, lr}

                ADR             r1, Stack
                LDR             r0, [r2, #WHandle]
                STR             r0, [r1]

; First up, check for any scrolling, and do a block move if necessary

                LDR             r0, [r2, #Scrolled]
                TEQ             r0, #0
                BLNE            RollUp

; Now do the updates

                ADD             r0, r2, #ChBox
                LDMIA           r0, {r3, r5-r7}

; Turn the changed box into a workarea rectangle

                MOV             r3, r3, LSL #4
                ADD             r3, r3, #LeftMargin

                MOV             r4, #0
                SUB             r4, r4, r7, LSL #5
                SUB             r4, r4, #TopMargin + 32

                MOV             r6, r6, LSL #4
                ADD             r6, r6, #LeftMargin + 16

                MOV             r7, #0
                SUB             r7, r7, r5, LSL #5
                SUB             r7, r7, #TopMargin

                STMIB           r1, {r3-r4, r6-r7}

                MOV             r3, #-1
                MOV             r4, #-1
                MOV             r5, #-1
                MOV             r6, #-1
                STMIA           r0, {r3-r6}

                SWIX            Wimp_UpdateWindow
                LDMVSFD         sp!, {r3-r7, pc}

UpdateW1        TEQ             r0, #0
                LDMEQFD         sp!, {r3-r7, pc}^

                BL              DrawBit

                SWIX            Wimp_GetRectangle
                B               UpdateW1

; Move the visible contents of the window by the required amount if a scroll has
; taken place

RollUp          STMFD           sp!, {r0-r7, lr}

                LDR             r7, [r2, #Scrolled]
                MOV             lr, #0
                STR             lr, [r2, #Scrolled]
                LDR             lr, [r2, #Offset]
                STR             lr, [r2, #DispOffset]

                SWIX            Wimp_GetWindowState
                LDMIA           r1, {r0-r6}

; Convert visible area to workarea coordinates

                SUB             r2, r2, r4
                SUB             r3, r3, r1
                MOV             r1, r5
                SUB             r4, r6, r7, LSL #5
                ADD             r6, r2, r6
                ADD             r3, r3, r5
                SUB             r2, r6, r7, LSL #5

                SWIX            Wimp_BlockCopy

                LDMFD           sp!, {r0-r7, pc}^

; Draw a bit of a window, Redraw block at R1, data at R2

DrawBit         STMFD           sp!, {r0-r11, lr}
                LDR             r7, [r1, #RB_BoxY1]
                LDR             r8, [r1, #RB_ScrY]

; R3 <== first row, R4 <== last row
;
; First row is Box.y1 - Wind.y1
;

                LDR             r3, [r1, #RB_WindY1]
                SUB             r3, r7, r3
                SUB             r3, r3, #TopMargin
                SUBS            r3, r3, r8
                MOV             r3, r3, ASR #5

                LDR             r4, [r1, #RB_WindY0]
                SUB             r4, r7, r4
                SUB             r4, r4, #TopMargin
                SUBS            r4, r4, r8
                MOV             r4, r4, ASR #5

; R5 <= first column, R6 <= last column

                LDR             r7, [r1, #RB_BoxX0]
                LDR             r8, [r1, #RB_ScrX]

                LDR             r5, [r1, #RB_WindX0]
                SUB             r5, r5, r7
                SUB             r5, r5, #LeftMargin
                ADDS            r5, r5, r8
                MOV             r5, r5, ASR #4

                LDR             r6, [r1, #RB_WindX1]
                SUB             r6, r6, r7
                SUB             r6, r6, #LeftMargin
                ADDS            r6, r6, r8
                MOV             r6, r6, ASR #4

; Limits of window

                LDR             r7, [r2, #MaxX]
                LDR             r8, [r2, #MaxY]

DrawBit1        CMP             r3, r4
                LDMGTFD         sp!, {r0-r11, pc}^

                BL              MoveTo

                CMP             r3, #-1
                CMPGT           r8, r3
                BLE             DrawBit3

; Calculate base address of row in R10

                LDR             r11, [r2, #DispOffset]    ; in lines
                ADD             r11, r11, r3
                CMP             r11, r8
                SUBHS           r11, r11, r8          ; wrap round
                MLA             r10, r7, r11, r2      ; * MaxX
                ADD             r10, r10, #WHeaderSize

                MOV             r9, r5
                MOV             r11, #0

DrawBit2        CMP             r9, r6
                BGT             DrawBit3
                CMP             r9, #-1
                CMPGT           r7, r9

                LDRGTB          r0, [r10, r9]
                MOVLE           r0, #" "
                ADD             r9, r9, #1

                TEQ             r0, #" "
                ADDEQ           r11, r11, #1
                BEQ             DrawBit2

; Non-space so flush it

                TEQ             r11, #0
                BLNE            MoveRight
                SWIX            OS_WriteC
                B               DrawBit2

DrawBit3        ADD             r3, r3, #1
                B               DrawBit1

MoveRight       STMFD           sp!, {r0-r2, lr}
                TEQ             r1, #1
                SWIX            OS_WriteI + " ", EQ
                MOVNE           r0, #0
                MOVNE           r1, r11, LSL #4
                MOVNE           r2, #0
                SWIX            OS_Plot, NE
                MOV             r11, #0
                LDMFD           sp!, {r0-r2, pc}^

; Row in R3, column in R5

MoveTo          STMFD           sp!, {r0-r2, r7-r9, lr}
                LDR             r7, [r1, #RB_BoxX0]
                LDR             r0, [r1, #RB_ScrX]
                SUB             r7, r7, r0
                ADD             r7, r7, #LeftMargin
                
                LDR             r8, [r1, #RB_BoxY1]
                LDR             r0, [r1, #RB_ScrY]
                SUB             r8, r8, r0
                SUB             r8, r8, #TopMargin

                LDR             r9, [r2, #Flags]

                MOV             r0, #0
                SWIX            Wimp_SetColour

                MOV             r0, #4
                ADD             r1, r7, r6, LSL #4
                ADD             r1, r1, #16
                SUB             r2, r8, r3, LSL #5
                SUB             r2, r2, #32

                SWIX            OS_Plot

                MOV             r0, #96 + 5
                ADD             r1, r7, r5, LSL #4
                SUB             r2, r8, r3, LSL #5
                SUB             r2, r2, #1

                SWIX            OS_Plot

                TST             r9, #IsOpen
                MOVEQ           r0, #3
                MOVNE           r0, #7
                SWIX            Wimp_SetColour

                LDMFD           sp!, {r0-r2, r7-r9, pc}^

; SWI Handling code

Tr_BadSWI       ADR             r0, BadSWI
                ORRS            pc, lr, #V_bit

BadSWI          ERROR           &101, "Bad Tracker SWI"

SWIHandler      LDR             ws, [ws]
                CMP             r11, #(SWIJumpEnd - SWIJump) / 4
                ADDLO           pc, pc, r11, LSL #2
                B               Tr_BadSWI

SWIJump         B               Tr_Open
                B               Tr_Close
                B               Tr_SetPos
                B               Tr_WriteS
                B               Tr_CLS
                B               Tr_Simple
SWIJumpEnd

; SWI handling routines
;
; r0 ==> title for tracker window (Tracker: <title>)
; r1 ==> width of window in characters
; r2 ==> height of window in characters
; r3 ==> flags as follows
;    bit 0  ==> treat LF as LFCR (useful for '\n' from C)
;
; r0 <== handle for future operations on this window

Tr_Open         TEQ             r1, #0
                TEQNE           r2, #0
                ADREQ           r0, TooSmall
                ORREQS          pc, lr, #V_bit

                STMFD           sp!, {r0-r9, lr}
                MUL             r3, r1, r2
                ADD             r3, r3, #WHeaderSize
                MOV             r0, #6
                SWIX            OS_Module
                ADRVS           r0, NoRoom
                STRVS           r0, [sp]
                LDMVSFD         sp!, {r0-r9, pc}

; Addressed by R2, initialise it

                MOV             r0, #-1
                MOV             r1, #WHeaderSize-4
Tr_Open1        STR             r0, [r2, r1]
                SUBS            r1, r1, #4
                BCS             Tr_Open1

                LDR             r0, NextHandle
                ADD             r0, r0, #1
                STR             r0, NextHandle        ; Handle
                LDR             r1, Windows           ; Link
                LDR             r3, [sp, #12]
                ORR             r3, r3, #IsOpen       ; Flags
                MOV             r4, #0                ; Scrolled
                MOV             r5, #0                ; Offset
                LDR             r6, [sp, #4]          ; MaxX
                LDR             r7, [sp, #8]          ; MaxY
                MOV             r8, #0                ; CurX
                MOV             r9, #0                ; CurY
                STMIA           r2, {r0-r1, r3-r9}
                STR             r5, [r2, #DispOffset] ; DispOffset

; Copy title

                ADR             r0, TitlePrefix
                ADD             r1, r2, #WTitle
Tr_Open2        LDRB            r3, [r0], #1
                TEQ             r3, #0
                STRNEB          r3, [r1], #1
                BNE             Tr_Open2

                LDR             r0, [sp, #0]
                MOV             r4, #TitleLen - :LEN: "Tracker: " - 1

Tr_Open3        SUBS            r4, r4, #1
                MOVEQ           r3, #0
                LDRNEB          r3, [r0], #1
                STRB            r3, [r1], #1
                CMP             r3, #" "
                BHS             Tr_Open3

; Now link the block in

                STR             r2, Windows
                      
                BL              doCLS
                                        
                LDMFD           sp!, {r0-r9, lr}
                LDR             r0, NextHandle
                MOVS            pc, lr

TitlePrefix     =               "Tracker: ", 0
                ALIGN

NoRoom          ERROR           &103, "No room in RMA to create Tracker window"
TooSmall        ERROR           &104, "Tracker window too small"

BadHandle       ERROR           &105, "Bad Tracker handle"

FindHandle      LDR             r2, Windows
FindHand1       TEQ             r2, #0
                ADREQ           r0, BadHandle
                ORREQS          pc, lr, #V_bit
                LDR             r1, [r2, #Handle]
                TEQ             r0, r1
                BICEQS          pc, lr, #V_bit
                LDR             r2, [r2, #Link]
                B               FindHand1

; Close merely marks a window as closeable

Tr_Close        STMFD           sp!, {r0-r2, lr}
                BL              FindHandle
                STRVS           r0, [sp]
                LDMVSFD         sp!, {r0-r2, pc}
                LDR             r0, [r2, #Flags]
                BIC             r0, r0, #IsOpen :OR: AutoGot
                ORR             r0, r0, #BeenClosed
                STR             r0, [r2, #Flags]
                LDMFD           sp!, {r0-r2, pc}^

; R0 ==> Handle
; R1 ==> X
; R2 ==> Y

Tr_SetPos       STMFD           sp!, {r0-r4, lr}
                BL              FindHandle
                STRVS           r0, [sp]
                LDMVSFD         sp!, {r0-r4, pc}
                ADD             r2, r2, #MaxX

                LDMIA           r2!, {r3, r4}
                LDMIB           sp, {r0, r1}
                CMP             r0, r3
                CMPLO           r1, r4
                LDMHSFD         sp!, {r0-r4, pc}^

                STMIA           r2, {r0, r1}
                LDMFD           sp!, {r0-r4, pc}^

; R0 ==> Handle
; R1 ==> String
;
; The string to be written is treated as a number of strings of printable
; characters punctuated by control codes.  The following codes are interpreted
;
;   08, 09, 0A, 0B, 0C, 0D, 7F
;
; all others are ignored.  Top bit set characters are processed normally

Tr_WriteS       STMFD           sp!, {r0-r2, lr}
                BL              FindHandle
                STRVS           r0, [sp]
                LDMVSFD         sp!, {r0-r2, pc}
                LDR             r1, [sp, #4]
Tr_WriteS1      LDRB            r0, [r1], #1
                TEQ             r0, #0
                LDMEQFD         sp!, {r0-r2, pc}^
                TEQ             r0, #&7F
                BLEQ            DelChar
                BEQ             Tr_WriteS1
                CMP             r0, #&1F
                BLLS            CtrlChar
                BLS             Tr_WriteS1
                BL              PutChar
                B               Tr_WriteS1

; DelChar is simulated with <bs><spc><bs>

DelChar         STMFD           sp!, {lr}
                MOV             r0, #8
                BL              CtrlChar
                MOV             r0, #" "
                BL              PutChar
                MOV             r0, #8
                BL              CtrlChar
                LDMFD           sp!, {pc}^

; Process 8, 9, 10, 11, 12, 13

CtrlChar        STMFD           sp!, {r0-r1, lr}

                TEQ             r0, #10
                TEQNE           r0, #13
                BNE             CtrlChar2
                LDR             r1, [r2, #Flags]
                TST             r1, #AutoNewLine
                BEQ             CtrlChar2

; Handle it

                TST             r1, #AutoGot
                BEQ             CtrlChar1

; Already know what it is

                TST             r1, #AutoIsCR
                MOVNE           lr, #13
                MOVEQ           lr, #10
                TEQ             lr, r0
                BEQ             cNewLine
                LDMFD           sp!, {r0-r1, pc}^

CtrlChar1       TEQ             r0, #13
                ORREQ           r1, r1, #AutoIsCR
                ORR             r1, r1, #AutoGot
                STR             r1, [r2, #Flags]
                B               cNewLine

CtrlChar2       SUBS            r0, r0, #8
                RSBHSS          lr, r0, #5
                ADDHS           pc, pc, r0, LSL #2
                LDMFD           sp!, {r0-r1, pc}^
                B               cBackSpace
                B               cTab
                B               cLineFeed
                B               cVTab
                B               cCls
                B               cCr

cBackSpace      LDR             r0, [r2, #CurX]
                SUBS            r0, r0, #1
                LDRLO           r0, [r2, #MaxX]
                SUBLO           r0, r0, #1
                STR             r0, [r2, #CurX]
                LDMHSFD         sp!, {r0-r1, pc}^

cVTab           LDR             r0, [r2, #CurY]
                SUBS            r0, r0, #1
                MOVLO           r0, #0
                STR             r0, [r2, #CurY]
                STRLO           r0, [r2, #CurX]
                LDMFD           sp!, {r0-r1, pc}^

Advance         STMFD           sp!, {r0-r1, lr}

cTab            LDR             r0, [r2, #CurX]
                LDR             r1, [r2, #MaxX]
                ADD             r0, r0, #1
                CMP             r0, r1
                MOVHS           r0, #0
                STR             r0, [r2, #CurX]
                LDMLOFD         sp!, {r0-r1, pc}^

cNewLine        MOV             r0, #0
                STR             r0, [r2, #CurX]

cLineFeed       LDR             r0, [r2, #CurY]
                LDR             r1, [r2, #MaxY]
                ADD             r0, r0, #1
                CMP             r0, r1
                SUBHS           r0, r1, #1
                STR             r0, [r2, #CurY]
                LDMLOFD         sp!, {r0-r1, pc}^

; Scroll 'screen' up by one line

                STMFD           sp!, {r3-r10}
                ADD             lr, r2, #Scrolled
                LDMIA           lr, {r0-r1, r3-r4}
                ADD             lr, r2, #ChBox
                LDMIA           lr, {r7-r10}

; Blank bottom line

                MLA             r5, r1, r3, r2
                ADD             r5, r5, #WHeaderSize
                MOV             r6, #" "
                MOV             lr, r3
Scrl1           STRB            r6, [r5], #1
                SUBS            lr, lr, #1
                BNE             Scrl1

; Bump Scrolled, Offset

                ADD             r0, r0, #1
                ADD             r1, r1, #1
                CMP             r1, r4
                SUBHS           r1, r1, r4

; Now update changed box

                SUB             r9, r3, #1
                SUB             r10, r4, #1

                CMP             r7, #-1
                MOVEQ           r8, r4
                SUBS            r8, r8, #1
                MOVMI           r8, #0
                MOV             r7, #0

                ADD             lr, r2, #Scrolled
                STMIA           lr, {r0-r1, r3-r4}
                ADD             lr, r2, #ChBox
                STMIA           lr, {r7-r10}
                LDMFD           sp!, {r3-r10}
                LDMFD           sp!, {r0-r1, pc}^

cCls            BL              doClear
                LDMFD           sp!, {r0-r1, pc}^

cCr             MOV             r0, #0
                STR             r0, [r2, #CurX]
                LDMFD           sp!, {r0-r1, pc}^

; Put the character in R0 at the current cursor position, update the cursor
; position and the changed box.

PutChar         STMFD           sp!, {r0-r11, lr}

                ADD             r1, r2, #Offset
                LDMIA           r1, {r3-r11}

; Update the changed box

                CMP             r8, #-1
                MOVEQ           r8, r6
                MOVEQ           r9, r7
                MOVEQ           r10, r6
                MOVEQ           r11, r7
                BEQ             PutChar1

                CMP             r8, r6
                MOVHI           r8, r6
                CMP             r9, r7
                MOVHI           r9, r7
                CMP             r10, r6
                MOVLO           r10, r6
                CMP             r11, r7
                MOVLO           r11, r7

PutChar1        ADD             r1, r2, #ChBox
                STMIA           r1, {r8-r11}

; Assume the cursor position is on the 'screen' initially
; R3 ==> offset
; R4 ==> MaxX    R5 ==> MaxY
; R6 ==> CurX    R7 ==> CurY

                ADD             r3, r3, r7            ; Actual Y
                CMP             r3, r5
                SUBHS           r3, r3, r5            ; Wrap
                MLA             r1, r3, r4, r6
                ADD             r1, r1, r2
                ADD             r1, r1, #WHeaderSize
                STRB            r0, [r1]
                BL              Advance
                LDMFD           sp!, {r0-r11, pc}^

doClear         STMFD           sp!, {r0-r6, lr}
                B               Tr_CLS1

Tr_CLS          STMFD           sp!, {r0-r6, lr}
                BL              FindHandle
                STRVS           r0, [sp]
                LDMVSFD         sp!, {r0-r6, pc}

Tr_CLS1         BL              doCLS

; Set the changed box

                ADD             r0, r2, #ChBox
                MOV             r3, #0
                MOV             r4, #0
                LDR             r5, [r2, #MaxX]
                SUB             r5, r5, #1
                LDR             r6, [r2, #MaxY]
                SUB             r6, r6, #1
                STMIA           r0, {r3-r6}
                LDMFD           sp!, {r0-r6, pc}^

doCLS           STMFD           sp!, {r0-r1, r3-r4, lr}
                MOV             r0, #0
                STR             r0, [r2, #CurX]
                STR             r0, [r2, #CurY]
                LDR             r0, [r2, #MaxX]
                LDR             r1, [r2, #MaxY]
                MUL             r0, r1, r0
                LDR             r1, = &20202020
                ADD             r3, r2, #WHeaderSize

                AND             r4, r0, #3
                BICS            r0, r0, #3
                BEQ             doCLS2

doCLS1          STR             r1, [r3], #4
                SUBS            r0, r0, #4
                BNE             doCLS1

doCLS2          TEQ             r4, #0
                LDMEQFD         sp!, {r0-r1, r3-r4, pc}^

doCLS3          STRB            r1, [r3], #1
                SUBS            r4, r4, #1
                BNE             doCLS3
                LDMFD           sp!, {r0-r1, r3-r4, pc}^

                LTORG

Tr_Simple       STMFD           sp!, {r0-r3, lr}
                LDR             r0, SimpleHandle
                TEQ             r0, #0
                BNE             Tr_Simple1

                ADR             r0, SimpleTitle
                MOV             r1, #80
                MOV             r2, #1000
                MOV             r3, #AutoNewLine
                SWIX            Tracker_Open
                STRVC           r0, SimpleHandle
                ADDVS           sp, sp, #4
                LDMVSFD         sp!, {r1-r3, pc}

Tr_Simple1      LDR             r1, [sp]
                SWIX            Tracker_WriteS
                LDMFD           sp!, {r0-r3, pc}^

SimpleTitle     =               "Automatic window", 0
                ALIGN

SWITable        =               "Tracker", 0
                =               "Open", 0
                =               "Close", 0
                =               "SetPos", 0
                =               "WriteS", 0
                =               "CLS", 0
                =               "Simple", 0
                =               0

; **************************************************************************
; *                                                                        *
; * Psuedo filing system                                                   *
; *                                                                        *
; **************************************************************************
;
; Filenames are like filename_100_32 to open a window 100 columns by 32 rows
; big.  If the size is ommitted the text size of the current screen mode is
; used.   When searching for existing files anything following an _ is
; ignored.

FSNumber        *               &40

FSInfoBlock     &               FSName     - ModuleBase
                &               0
                &               FSOpen     - ModuleBase
                &               FSGetBytes - ModuleBase
                &               FSPutBytes - ModuleBase
                &               FSArgs     - ModuleBase
                &               FSClose    - ModuleBase
                &               FSFile     - ModuleBase
                &               FSNumber
                &               FSFunc     - ModuleBase
                &               FSGBPB     - ModuleBase

; Open a file

FSOpen          TEQ             r0, #1
                BEQ             CreateOpen
                TEQ             r0, #2
                MOVNE           r1, #0
                MOVNES          pc, lr

; Open an existing window

ReOpen          STMFD           sp!, {lr}
                BL              FSLeafName
                BL              FSFindName
                LDMFD           sp!, {lr}
                TEQ             r2, #0
                MOVEQ           r1, #0
                BICEQS          pc, lr, #V_bit

                LDR             r1, [r2, #Flags]
                TST             r1, #IsOpen
                ADRNE           r0, AlreadyOpen
                ORRNES          pc, lr, #V_bit

                MOV             r0, #1 :SHL: 31
                ORR             r1, r1, #IsOpen :OR: BeenClosed
                STR             r1, [r2, #Flags]
                LDR             r1, [r2, #Handle]
                MOV             r2, #0
                BICS            pc, lr, #V_bit

AlreadyOpen     ERROR           &108C2, "Already open"

CreateOpen      STMFD           sp!, {lr}
                BL              CreateFile
                MOVVC           r0, #1 :SHL: 31
                MOVVC           r2, #0
                LDMFD           sp!, {pc}^

GetNumber       TEQ             r0, #"_"
                ORRNES          pc, lr, #C_bit
                MOV             r2, #0
                ORR             lr, lr, #C_bit

GetNumber1      LDRB            r0, [r1], #1
                CMP             r0, #"0"
                RSBHSS          r3, r0, #"9"
                BICLOS          pc, lr, #C_bit

                SUB             r0, r0, #"0"
                ADD             r2, r2, r2, LSL #2
                ADD             r2, r0, r2, LSL #1
                BIC             lr, lr, #C_bit
                B               GetNumber1

; Create a new window.  Size is specified by filename or screen size

CreateFile      STMFD           sp!, {r0-r2, r6-r8, lr}
                BL              FSLeafName
                STR             r1, [sp, #Word * 1]
                BL              FSFindName
                TEQ             r2, #0
                BEQ             CreateF1
                BL              ReOpen
                STRVS           r0, [sp, #Word * 0]
                STRVC           r1, [sp, #Word * 1]
                LDMFD           sp!, {r0-r2, r6-r8, pc}

; Find out how long the first bit of the name is

CreateF1        MOV             r8, #0
CreateF2        LDRB            r0, [r1], #1
                TEQ             r0, #0
                TEQNE           r0, #"_"
                ADD             r8, r8, #1
                BNE             CreateF2

; Now check for possible _width_height; anything else after the _ is simply
; ignored.

                BL              GetNumber
                BCS             CreateF3
                MOV             r6, r2                   ; width
                BL              GetNumber
                MOVCC           r7, r2                   ; height
                BCC             CreateF4

; Calculate width and height

CreateF3        MOV             r0, #-1
                MOV             r1, #1
                SWIX            OS_ReadModeVariable
                ADD             r6, r2, #1
                MOVEQ           r1, #2
                SWIX            OS_ReadModeVariable, EQ
                ADDEQ           r7, r2, #1

; Now stick the name onto the stack, and create the window

CreateF4        ADD             r8, r8, #3
                BIC             r8, r8, #3
                LDR             r1, [sp, #Word * 1]
                SUB             sp, sp, r8
                MOV             r0, sp

CreateF5        LDRB            lr, [r1], #1
                TEQ             lr, #"_"
                MOVEQ           lr, #0
                TEQ             lr, #0
                STRB            lr, [r0], #1
                BNE             CreateF5

                MOV             r0, sp
                MOV             r1, r6
                MOV             r2, r7
                MOV             r3, #AutoNewLine

                SWIX            Tracker_Open
                ADD             sp, sp, r8
                STRVC           r0, [sp, #Word * 1]
                STRVS           r0, [sp, #Word * 0]

                LDMFD           sp!, {r0-r2, r6-r8, pc}^

; Handle *Create and similar

MakeFile        STMFD           sp!, {lr}
                BL              CreateFile
                MOVVC           r0, r1
                SWIX            Tracker_Close, VC
                LDMFD           sp!, {pc}

FSGetBytes      ORRS            pc, lr, #C_bit

FSPutBytes      STMFD           sp!, {r0-r1, lr}
                MOV             r0, r1
                MOV             r1, sp
                SWIX            Tracker_WriteS
                STRVS           r0, [sp]
                LDMFD           sp!, {r0-r1, pc}

FSArgs          CMP             r0, #(FSArgsTabEnd - FSArgsTab) / 4
                ADDCC           pc, pc, r0, LSL #2
                BICS            pc, lr, #V_bit

FSArgsTab       B               ReadPtr
                BICS            pc, lr, #V_bit
                B               ReadPtr
                BICS            pc, lr, #V_bit
                B               ReadAlloc
                BICS            pc, lr, #V_bit :OR: C_bit
                BICS            pc, lr, #V_bit
                BICS            pc, lr, #V_bit
                BICS            pc, lr, #V_bit
                B               ReadDate
FSArgsTabEnd

ReadPtr         MOV             r2, #0
                BICS            pc, lr, #V_bit

ReadAlloc       LDR             r2, = &7FFFFFFF
                BICS            pc, lr, #V_bit

                LTORG

ReadDate        MOV             r2, #0
                MOV             r3, #0
                BICS            pc, lr, #V_bit

FSClose         STMFD           sp!, {r0, lr}
                MOV             r0, r1
                SWIX            Tracker_Close
                LDMFD           sp!, {r0, pc}

FSFile          TEQ             r0, #255
                MOVEQ           r0, #10
                CMP             r0, #(FSFileTabEnd - FSFileTab) / 4
                ADDCC           pc, pc, r0, LSL #2
                BICS            pc, lr, #V_bit

FSFileTab       B               FileSave             ; Save file
                BICS            pc, lr, #V_bit       ; Write catalogue info
                BICS            pc, lr, #V_bit       ; Write load address
                BICS            pc, lr, #V_bit       ; Write execution address
                BICS            pc, lr, #V_bit       ; Write attributes
                B               GetInfo              ; Read catalogue info
                BICS            pc, lr, #V_bit       ; Delete object
                B               MakeFile             ; Create file
                BICS            pc, lr, #V_bit       ; Create directory
                BICS            pc, lr, #V_bit       ; Read catalogue info
                BICS            pc, lr, #V_bit       ; Load file
FSFileTabEnd

; Synthesize it by opening the file, outputting to it, then closing it

FileSave        STMFD           sp!, {r0-r1, r4, lr}
                BL              CreateFile
                BVS             FileSave3
                LDMVSFD         sp!, {r0-r1, r4, pc}
FileSave1       CMP             r4, r5
                BGE             FileSave2
                LDRB            r0, [r4], #1
                BL              FSPutBytes
                BVS             FileSave3
                B               FileSave1
FileSave2       MOV             r0, r1
                SWIX            Tracker_Close
FileSave3       STRVS           r0, [sp, #Word * 0]
                LDMFD           sp!, {r0-r1, r4, pc}

GetInfo         STMFD           sp!, {lr}
                BL              FSLeafName
                BL              FSFindName
                TEQ             r2, #0
                MOVEQ           r0, #0
                LDMEQFD         sp!, {pc}

                LDR             r4, [r2, #MaxX]
                LDR             r5, [r2, #MaxY]
                MUL             r4, r5, r4
                MOV             r0, #1
                MOV             r2, #&FFFFFF00
                MOV             r3, #&00000000
                MOV             r5, #2_00100010
                LDMFD           sp!, {pc}

FSFunc          CMP             r0, #(FSFuncTabEnd - FSFuncTab) / 4
                ADDCC           pc, pc, r0, LSL #2
                BICS            pc, lr, #V_bit

FSFuncTab       BICS            pc, lr, #V_bit
                BICS            pc, lr, #V_bit
                B               CatAll
                B               CatAll
                B               CatAll
                B               CatAll
                B               CatSome
                BICS            pc, lr, #V_bit
                BICS            pc, lr, #V_bit            ; Rename object
                BICS            pc, lr, #V_bit            ; Access
                BICS            pc, lr, #V_bit            ; Boot FS
                BICS            pc, lr, #V_bit            ; Read disc name
                B               GetCSD                    ; Read CSD
                B               GetCSD                    ; Read CSL
                B               GetNames                  ; Read directory
                B               GetNames      
                BICS            pc, lr, #V_bit
                BICS            pc, lr, #V_bit
                BICS            pc, lr, #V_bit
                B               GetNames
                B               CatSome
FSFuncTabEnd

CatAll          STMFD           sp!, {r0, r2, lr}
                LDR             r2, Windows
CatAll1         TEQ             r2, #0
                LDMEQFD         sp!, {r0, r2, pc}^
                ADD             r0, r2, #WTitle + :LEN: "Tracker: "
                SWIX            OS_Write0
                SWIX            OS_NewLine
                LDR             r2, [r2, #Link]
                B               CatAll1

CatSome         STMFD           sp!, {r0, r2, lr}
                LDR             r2, Windows
CatSome1        TEQ             r2, #0
                LDMEQFD         sp!, {r0, r2, pc}^
                ADD             r0, r2, #WTitle + :LEN: "Tracker: "
                BL              FSNameMatch
                SWIX            OS_Write0, CC
                SWIX            OS_NewLine, CC
                LDR             r2, [r2, #Link]
                B               CatSome1

RootName        =               0, 1, "$", 0

GetCSD          LDR             r0, RootName
                STR             r0, [r2]
                BICS            pc, lr, #V_bit

GetNames        STMFD           sp!, {r0-r2, r5-r8, lr}
                MOV             r6, r3           ; number to read
                MOV             r3, #0
                LDR             r1, Windows
GetNames1       TEQ             r1, #0
                MOVEQ           r4, #-1
                LDMEQFD         sp!, {r0-r2, r5-r8, pc}^
                SUBS            r4, r4, #1
                LDRHS           r1, [r1, #Link]
                BHS             GetNames1

; R1 points to first one to read

GetNames2       TEQ             r1, #0
                MOVEQ           r4, #-1
                TEQNE           r6, #0
                LDMEQFD         sp!, {r0-r2, r5-r8, pc}^

                ADD             r8, r1, #WTitle + :LEN: "Tracker: "
                MOV             r7, #1
GetNames3       LDRB            lr, [r8], #1
                CMP             lr, #" "
                TEQHI           lr, #"_"
                BLS             GetNames4
                ADD             r7, r7, #1
                B               GetNames3

GetNames4       TEQ             r0, #15
                ADDEQ           r7, r7, #3 + 5 * Word
                TEQ             r0, #19
                ADDEQ           r7, r7, #3 + 7 * Word
                TEQ             r0, #14
                BICNE           r7, r7, #3

                CMP             r7, r5
                LDMEQFD         sp!, {r0-r2, r5-r8, pc}^

                SUB             r5, r5, r7
                ADD             r3, r3, #1
                ADD             r4, r4, #1

                TEQ             r0, #14
                BEQ             GetNames5
                MOV             lr, #&FFFFFF00
                STR             lr, [r2], #4
                MOV             lr, #0
                STR             lr, [r2], #4
                LDR             r8, [r1, #MaxX]
                LDR             lr, [r1, #MaxY]
                MUL             lr, r8, lr
                STR             lr, [r2], #4
                MOV             lr, #2_00100010
                STR             lr, [r2], #4
                MOV             lr, #1
                STR             lr, [r2], #4
                TEQ             r0, #19
                MOVEQ           lr, #0
                STREQ           lr, [r2], #4
                STREQ           lr, [r2], #4

GetNames5       ADD             r8, r1, #WTitle + :LEN: "Tracker: "
GetNames6       LDRB            lr, [r8], #1
                CMP             lr, #" "
                TEQHI           lr, #"_"
                MOVLSS          lr, #0
                STRB            lr, [r2], #1
                BNE             GetNames6
                TEQ             r0, #14
                ADDNE           r2, r2, #3
                BICNE           r2, r2, #3

                SUB             r6, r6, #1
                LDR             r1, [r1, #Link]
                B               GetNames2

FSGBPB          BICS            pc, lr, #V_bit

FSName          =               "TrackFS", 0

; Support routines

; R1 ==> Pointer to filename
;
; On exit
;
; R1 ==> Pointer to leafname

FSLeafName      STMFD           sp!, {r0, lr}
                MOV             r0, r1
FSLeaf1         LDRB            lr, [r0], #1
                CMP             lr, #" "
                LDMLSFD         sp!, {r0, pc}^
                TEQ             lr, #"."
                TEQNE           lr, #":"
                MOVEQ           r1, r0
                B               FSLeaf1

; R1 ==> Pointer to ctrl terminated filename
;
; On exit
;
; R2 ==> Pointer to the window which owns it, or 0 if no match found

FSFindName      STMFD           sp!, {r0, lr}
                LDR             r2, Windows
FSFindName1     TEQ             r2, #0
                LDMEQFD         sp!, {r0, pc}^
                ADD             r0, r2, #WTitle + :LEN: "Tracker: "
                BL              FSNameMatch
                LDMCCFD         sp!, {r0, pc}^
                LDR             r2, [r2, #Link]
                B               FSFindName1

; Macro: convert character to upper case

                MACRO
$label          UPC             $reg, $temp
$label          CMP             $reg, #"a"
                RSBHS           $temp, $reg, #"z"
                SUBHS           $reg, $reg, #"a"-"A"
                MEND

; Perform a wildcard name match
;
; R0 ==> Name to match with
; R1 ==> Wildcard
;
; On exit, C=0 if success


FSNameMatch     BIC             lr, lr, #C_bit
                STMFD           sp!, {r0-r3, lr}
FSNameMatch1    LDRB            r2, [r0], #1
                LDRB            r3, [r1], #1
                CMP             r2, #" "
                BLS             FSNameMatch2
                TEQ             r2, #"_"
                BNE             FSNameMatch3
FSNameMatch2    CMP             r3, #" "
                TEQHI           r3, #"_"
                LDMLSFD         sp!, {r0-r3, pc}^

FSNameMatch3    TEQ             r3, #"#"
                BEQ             FSNameMatch1
                TEQ             r3, #"*"
                BEQ             FSNameMatch4

                UPC             r2, lr
                UPC             r3, lr

                TEQ             r2, r3
                BEQ             FSNameMatch1

; Exit with C=1 to indicate failure

                LDMFD           sp!, {r0-r3, lr}
                ORRS            pc, lr, #C_bit

; Handle wildcard, matches zero or more characters

FSNameMatch4    SUB             r0, r0, #1

FSNameMatch5    BL              FSNameMatch
                LDMCCFD         sp!, {r0-r3, pc}^
                LDRB            r2, [r0], #1
                CMP             r2, #" "
                TEQHS           r2, #"_"
                BHS             FSNameMatch5

                LDMFD           sp!, {r0-r3, lr}
                ORRS            pc, lr, #C_bit

; Create and Kill trackfs

MakeFS          STMFD           sp!, {r0-r3, lr}
                MOV             r0, #12
                ADRL            r1, ModuleBase
                LDR             r2, =FSInfoBlock - ModuleBase
                MOV             r3, ws
                SWIX            OS_FSControl
                STRVS           r0, [sp]
                LDMFD           sp!, {r0-r3, pc}

RemoveFS        STMFD           sp!, {r0-r1, lr}
                MOV             r0, #16
                ADR             r1, FSName
                SWIX            OS_FSControl
                LDMFD           sp!, {r0-r1, pc}

RMAShrink       STMFD           sp!, {r0-r1, lr}
                MOV             r0, #1
                LDR             r1, =-16 * 1024 * 1024
                SWIX            OS_ChangeDynamicArea
                LDMFD           sp!, {r0-r1, pc}^

                LTORG
                
                =               "Andy"

                END
