In   -
Out  fileio
Type AOF
Ver  1.00n

Define Workspace
 Name    file
 Default r2
  handle  !   the file handle
End Workspace

Pre
 eof=-1
End Pre

#Area "JFP:FileIO" Code ReadOnly
#Rem Off
; *******************************************************************
; Subroutine:   fopen
; Description:  Open a file
; Parameters:   r0-> filename
;               r1-> mode string (r or w)
; Returns:      pointer to file block, or 0 if error
; *******************************************************************
.|fopen|
   STMFD   (sp)!,{r1-r3,link}            ; Stack registers
   MOV     r3,r1                         ; r3->mode
   MOV     r1,r0                         ; r1->filename
   LDRB    r2,[r3],#1                    ; read the file mode
   CMP     r2,#ASC("w")                  ; is it write ?
   MOVEQ   r0,#&80                       ; if so create it
   MOVNE   r0,#&40                       ; if not, it's read (or append)
   LDR     r14,[r3],#1                   ; read the next char
   CMP     r14,#ASC("+")                 ; is it + ?
   CMPEQ   r0,#&40                       ; and are we reading ?
   MOVEQ   r0,#&C0                       ; if so, make it r/w
   REM     "Opening %$1 with access %r0"
   XSWI    "XOS_Find"                    ; open it
   CMP     r0,#0                         ; did it open ?
   LDMEQFD (sp)!,{r1-r3,pc}              ; if not, return with 0
   MOV     r1,r0                         ; r1 = handle
   CMP     r2,#ASC("a")                  ; was it 'append' ?
   BNE     $notappend                    ; if not, skip the 'move to end'
   XSWI    "XOS_Args",2                  ; read extent
   XSWI    "XOS_Args",1                  ; write it pointer
$notappend
#MapWS file,r0
   XBL     |malloc|,`len_file            ; claim some space for the block
   STRW    r1,handle                     ; store it in the block
   LDMFD   (sp)!,{r1-r3,pc}              ; return with block in r0

; *******************************************************************
; Subroutine:   fclose
; Description:  close an open file
; Parameters:   r0-> block
; Returns:      r0 = 0
; *******************************************************************
#MapWS file
.|fclose|
   CMP     r0,#0                         ; is it null ?
   MOVEQ   pc,link                       ; return if so
   STMFD   (sp)!,{r1-r2,link}            ; Stack registers
   MOV     r2,r0                         ; r1-> block
   LDRW    r1,handle                     ; read the handle
   XSWI    "OS_Find",0                   ; close the file
   XBL     |free|,r2                     ; free it
   MOV     r0,#0                         ; return 0
   LDMFD   (sp)!,{r1-r2,pc}              ; Return from call

; *******************************************************************
; Subroutine:   fgetc
; Description:  Get a character
; Parameters:   r0-> block
; Returns:      r0 = character, or eof if error
; *******************************************************************
.|fgetc|
   CMP     r0,#0                         ; is it null ?
   MVNEQ   r0,#NOT eof                   ; if so, return eof
   MOVEQ   pc,link                       ; and return
   STMFD   (sp)!,{r1,link}               ; Stack registers
#MapWS file,r0
   LDRW    r1,handle                     ; read the handle
   XSWI    "OS_BGet"                     ; close the file
   MVNCS   r0,#NOT eof                   ; return eof if nothing read
   LDMFD   (sp)!,{r1,pc}                 ; Return from call

; *******************************************************************
; Subroutine:   putc
; Description:  Write character to the screen
; Parameters:   r0 = character
; Returns:      none
; *******************************************************************
.|putc|
   STMFD   (sp)!,{link}                  ; Stack registers
   CMP     r0,#10                        ; was it newline ?
   SWIEQ   "OS_NewLine"                  ; if so, dump a newline up there
   SWINE   "OS_WriteC"                   ; write it
   LDMFD   (sp)!,{pc}                    ; Return from call

; *******************************************************************
; Subroutine:   getc
; Description:  Get a character from the keyboard
; Parameters:   none
; Returns:      r0 = character
; *******************************************************************
.|getc|
   STMFD   (sp)!,{link}                  ; Stack registers
   SWI     "OS_ReadC"                    ; read it
   LDMFD   (sp)!,{pc}                    ; Return from call

; *******************************************************************
; Subroutine:   gets
; Description:  Read a string from the keyboard
; Parameters:   str-> string buffer
; Returns:      pointer to string
; *******************************************************************
.|gets|
   STMFD   (sp)!,{r0-r2,link}            ; Stack registers
   MOV     r2,r0                         ; r2-> string block
   MOV     r1,#0                         ; length of string
$loop
   SWI     "OS_ReadC"                    ; read a string
   MOVCS   r0,#27                        ; if error, return 27
   CMP     r0,#27                        ; is it escape ?
   CMPNE   r0,#10                        ; or newline ?
   CMPNE   r0,#13                        ; or return ?
   STRB    r0,[r2,r1]                    ; store the char
   ADD     r1,r1,#1                      ; increment length
   BEQ     $eos                          ; end of string
   CMP     r0,#ASC("U")-64               ; is it ctrl-U (delete all)
   SUBEQ   r1,r1,#1                      ; remove the delete if so
   BLEQ    $deleteall                    ; delete the line

   CMP     r0,#8                         ; is it backspace ?
   MOVEQ   r0,#127                       ; if so, use delete
   CMP     r0,#127                       ; is it delete ?
   SUBEQ   r1,r1,#2                      ; go back two (remove del and last)

   CMP     r0,#32                        ; is it a ctrl character
   SUBLT   r1,r1,#1                      ; if so, don't keep it
   BLT     $loop                         ; got for the next one

   SWI     "OS_WriteC"                   ; write it out
   B       $loop                         ; and go around again
$eos
   CMP     r0,#10                        ; is it newline ?
   CMPNE   r0,#13                        ; or return ?
   SUBEQ   r1,r1,#1                      ; if so, go back one
   MOV     r0,#0                         ; zero terminator
   STRB    r0,[r2,r1]                    ; store it
   SWI     "OS_NewLine"                  ; next line
   LDMFD   (sp)!,{r0-r2,pc}              ; Return from call
; delete all the string
$deleteall
   CMP     r1,#0                         ; is that it ?
$deleteloop
   BEQ     $loop                         ; if so, jump out
   SWI     &100+127                      ; delete a character
   SUBS    r1,r1,#1                      ; go back one
   B       $deleteloop                   ; and check the next
