NEW
  AUTO 3,1
*/--------------------------------------
* # putchar (BLOCKING)
* Print A (char) to StdOut
* ## C
* `int putchar ( int character );`
* ## ASM
* **In:**
* `lda character`
* `>SYSCALL putchar`
* ## RETURN VALUE 
* CC = success
*\--------------------------------------
K.PutChar		>PUSHA					character

				ldy #S.PS.hStdOut
				lda	(pPs),y
				jsr K.FPutC
				bcc K.PutChar.RTS

				tay 					E.NODATA
				bpl K.PutChar.RTS

				inc						0 = BLOCKING

K.PutChar.RET1	inc pStack

K.PutChar.RTS	rts
*/--------------------------------------
* # fputc (BLOCKING)
* Print A (char) to hFILE
* ## C
* `int fputc ( hFILE stream , int character );`
* ## ASM
* **In:**
* `>PUSHB character`
* `lda stream`
* `>SYSCALL fputc`
* ## RETURN VALUE 
* CC = success
*\--------------------------------------
K.FPutC			jsr PFT.CheckNodeA
				bcs K.PutChar.RET1

				lda (pStack)			character
				sta K.IOBuf

				lda #0
				>PUSHA
				inc						write 1 byte
				>PUSHA

				>PUSHWI K.IOBuf			buf
				jsr UNISTD.Write
				bcc K.PutChar.RET1		pop char...
				tay						E.NODATA
				bpl K.PutChar.RET1

				inc						0 = BLOCKING
*				sec
				rts
*/--------------------------------------
* # puts (BLOCKING)
* Write Str to StdOut, appends '\r\n'
* ## C
* `int puts ( const char * str );`
* **In:**
* ## ASM
* `>LDYAI str`
* `>SYSCALL puts`
* ## RETURN VALUE 
* CC = success
*\--------------------------------------
K.PutS			>STYA ZPPtr2

				ldy #0

.1				lda (ZPPtr2),y
				beq .2
				sta K.IOBuf,y
				iny
				bne .1

.9				lda #E.BUF
				sec
				rts

.2				lda #C.CR
				sta K.IOBuf,y
				iny
				beq .9

				lda #C.LF
				sta K.IOBuf,y

				iny
				beq .9

				lda #0
				sta K.IOBuf,y

				>PUSHWI K.IOBuf

				ldy #S.PS.hStdOut
				lda	(pPs),y
				jsr K.FPutS
				bcc K.PutS.RTS
				tay
				bne K.PutS.RTS			0 = BLOCKING

*				sec

K.PutS.RET2		>POP 2					pop K.IOBuf
K.PutS.RTS		rts
*/--------------------------------------
* # fputs (BLOCKING)
* Write Str to hFILE
* ## C
* `int fputs (hFILE stream, const char * str );`
* ## ASM
* **In:**
* `>PUSHW str`
* `lda stream`
* `>SYSCALL fputs`
* ## RETURN VALUE 
* CC = success
*\--------------------------------------
K.FPutS			jsr PFT.CheckNodeA		set IO.hFD
				bcs K.PutS.RET2

				lda (pStack)
				sta ZPPtr2				Get String
				ldy #1
				lda (pStack),y
				sta ZPPtr2+1
*				ldy #0
				dey
				ldx #0
.1				lda (ZPPtr2),y
				beq .2
				iny
				bne .1
				inx
				bra .1
.2				txa
				>PUSHA					push len HI

				tya
				>PUSHA					push len LO

				>PUSHW ZPPtr2
				jsr UNISTD.Write
				bcc K.PutS.RET2
				tay
				bpl K.PutS.RET2			IO Erorr
				inc						0 = BLOCKING
*				sec
K.FPutS.RTS		rts			
*/--------------------------------------
* # fgets (BLOCKING)
* read bytes from stream into the array
* pointed to by s, until n-1 bytes are read, or a <newline> is read and
* transferred to s, or an end-of-file condition is encountered. The
* string is then terminated with a null byte.
* ## C
* `char *fgets(hFILE stream, char * s, int n);`
* ## ASM
* **In:**
* `>PUSHW n`
* `>PUSHW s`
* `lda hFILE`
* `>SYSCALL fgets`
* ## RETURN VALUE 
*  Y,A: s 
* CC = success
*\--------------------------------------
* (pStack)+2	n
* (pStack)+0	s
*--------------------------------------
K.FGetS			jsr PFT.CheckNodeA
				bcs K.FPutS.RTS

				lda (pStack)
				sta ZPPtr2				s LO
				ldy #1
				lda (pStack),y
				sta ZPPtr2+1			s HI

				iny
				lda (pStack),y			n LO
				sta ZPPtr1

				iny
				lda (pStack),y			n HI
				sta ZPPtr1+1
				bmi .3					already something in buffer
			
.1				jsr STDIO.Read.1
				bcc .2
				cmp #MLI.E.EOF
				beq .9

				tay
				bpl .9					IO error
				inc						NO DATA -> BLOCKING
				rts
.2				lda K.IOBuf
				cmp #C.LF				Discard any leading LF
				beq .1

				cmp #C.CR
				beq .8					empty string

				jsr SHARED.PutCharPtr2

				lda ZPPtr1
				eor #$ff
				sta ZPPtr1

				lda ZPPtr1+1
				eor #$ff
				sta ZPPtr1+1
.3				inc ZPPtr1
				bne .4
				inc ZPPtr1+1
				beq .8					Buffer full
			
.4				jsr STDIO.Read.1
				bcs .5

				lda K.IOBuf
				cmp #C.CR
				beq .8
				jsr SHARED.PutCharPtr2
				bra .3
.5				cmp #MLI.E.EOF
				beq .8					String terminated by EOF
				tay
				bpl .9					I/O error

				lda ZPPtr2				NO DATA, but string not yet terminated
				sta (pStack)			s

				ldy #1
				lda ZPPtr2+1
				sta (pStack),y			s

				iny
				lda ZPPtr1
				sta (pStack),y			!n LO

				iny
				lda ZPPtr1+1
				sta (pStack),y			!n HI

				lda #0					BLOCKING
				sec
				rts

.8				lda #0
				sta (ZPPtr2)			terminate string
				clc
.9				>RET 4
*/--------------------------------------
* # getchar (BLOCKING)
* Get char from StdIn
* ## C
* `int getchar ();`
* ## ASM
* **In:**
* `>SYSCALL getchar`
* ## RETURN VALUE 
*  CC = success
*   A = char
*\--------------------------------------
K.GetChar		ldy #S.PS.hStdIn
				lda	(pPs),y		
*/--------------------------------------
* # getc (BLOCKING)
* Get char from Node
* ## C
* `int getc ( hFILE stream );`
* ## ASM
* **In:**
* `lda stream`
* `>SYSCALL getc`
* ## RETURN VALUE 
*  CC = success
*   A = char
*\--------------------------------------
K.GetC			jsr PFT.CheckNodeA
				bcs K.GetC.RTS

				jsr STDIO.Read.1
				bcc .8
				tay
				bpl K.GetC.RTS			I/O error

				inc						0 = BLOCKING
				rts

.8				lda K.IOBuf

K.GetC.RTS		rts
*--------------------------------------
STDIO.Read.1	lda #0
				>PUSHA
				inc						read 1 byte
				>PUSHA
				>PUSHWI K.IOBuf
				jmp UNISTD.READ
*/--------------------------------------
* # FOpen
* Open a file
* ## C
* `short int fopen ( const char *filename, short int flags, short int ftype, int auxtype );`
* **In:**
* ## ASM
* `>PUSHW filename`
* `>PUSHB flags`
*  + O.RDONLY : if R and !exists -> ERROR
*  + O.WRONLY : if W and !exists -> CREATE
*  + O.TRUNC : Reset Size To 0
*  + O.APPEND : Append
*  + O.TEXT   : Open/Append in Text mode
*  + O.CREATE : Create if not exists
* `>PUSHB ftype`
* `>PUSHW auxtype`
* TODO: replace flags/ftype/auxtype with mode="w+,t=TYP,x=AUXTYPE"
*  + r  = O_RDONLY
*  + r+ = O_RDWR
*  + w  = O_WRONLY | O_CREAT | O_TRUNC
*  + w+ = O_RDWR | O_CREAT | O_TRUNC
*  + a  = O_WRONLY | O_CREAT | O_APPEND
*  + a+ = O_RDWR | O_CREAT | O_APPEND
*  + ,t=123 or t=$ff or t=TXT
*  + ,x=12345 or x=$ffff
* ## RETURN VALUE 
*  CC : A = hFILE
*  CS : A = EC
*\--------------------------------------
K.FOpen			jsr PFT.CheckPath4
				bcs K.FOpen.RET4

				>PULLW IO.Open.AUXTYPE
				>PULLB IO.Open.TYPE
				>PULLB IO.Open.FLAGS
				
				inc pStack				discard filename
				inc pStack
				
				jsr UNISTD.Open
				bcs K.FClose.RTS

				jsr STDIO.NewHFile
				bcc K.FClose.RTS

				jmp IO.Open.ERR

K.FOpen.RET4	>RET 4
*/--------------------------------------
* # FClose
* Close a file
* ## C
* int fclose ( hFILE stream );
* ## ASM
* **In:**
* `lda stream`
* `>SYSCALL fclose`
* ## RETURN VALUE
*\--------------------------------------
K.FClose		jsr PFT.CheckNodeA
				bcs K.FClose.RTS

				sta .1+1				store hFile

				jsr UNISTD.Close
				bcs K.FClose.RTS

.1				ldx #$ff				SELF MODIFIED
				stz OF.Table.hFD-1,x

				lda OF.Table.hPath-1,x
				beq K.FClose.RTS		special files have no path 

				stz OF.Table.hPath-1,x
				jmp K.FreeMem			discard filename
*/--------------------------------------
* # FRead (BLOCKING)
* Read bytes from file
* ## C
* int fread (hFILE stream, void * ptr, int count );
* ## ASM
* **In:**
* `>PUSHWI count`
* `>PUSHW ptr`
* `lda stream`
* `>SYSCALL fread`
* ## RETURN VALUE
*  Y,A = Bytes Read
*\--------------------------------------
K.FRead			jsr PFT.CheckNodeA
				bcs K.FOpen.RET4

				jsr UNISTD.Read
				bcs K.FWrite.9

K.FClose.RTS	rts			
*/--------------------------------------
* # FWrite (BLOCKING)
* Write bytes to file
* ## C
* `int fwrite (hFILE stream, const void * ptr, int count );`
* ## ASM
* **In:**
* `>PUSHWI count`
* `>PUSHW ptr`
* `lda stream`
* `>SYSCALL fwrite`
* ## RETURN VALUE
*  Y,A = Bytes Written
*\--------------------------------------
K.FWrite		jsr PFT.CheckNodeA
				bcs K.FOpen.RET4

				jsr UNISTD.Write
				bcc K.FWrite.RTS

K.FWrite.9		tay
				bpl K.FWrite.RTS

				dec pStack				FF = NODATA
				dec pStack
				dec pStack
				dec pStack				keep ptr & count on stack
				inc						0 = BLOCKING

K.FWrite.RTS	rts
*/--------------------------------------
* # FFlush
* ## C
* int fflush(hFILE stream);
* ## ASM
* **In:**
* `lda stream`
* `>SYSCALL fflush`
*\--------------------------------------
K.FFlush		jsr PFT.CheckNodeA
				bcs .9

				lda (pFD)
				bne STDIO.IOERR
				>MLICALL MLIFLUSH
.9				rts
*--------------------------------------
STDIO.IOERR		lda #MLI.E.IO
				sec
				rts
*/-------------------------------------
* # FSeek
* Set the file-position indicator for hFILE
* ## C
* `int fseek(hFILE stream, long offset, short int whence);`
* ## ASM
* **In:**
* `>PUSHBI whence`
* `>PUSHL offset`
* `lda stream`
* `>SYSCALL fseek`
*\-------------------------------------
K.FSeek			jsr PFT.CheckNodeA
				bcc .11

				>RET 5

.11				lda (pFD)
				bne STDIO.IOERR
				>PULLL ACC32
				>PULLA					whence
				cmp #SEEK.END
				beq .30
				bcs .98

				dec
				beq .20

				stz K.MLI.PARAMS+2
				stz K.MLI.PARAMS+3
				stz K.MLI.PARAMS+4
				bra .8

* SEEK.CUR
.20				>MLICALL MLIGETMARK
				bcc .8
				rts

* SEEK.END
.30				>MLICALL MLIGETEOF
				bcs .9

.8				ldy #0

				clc

.81				lda K.MLI.PARAMS+2,y
				adc ACC32,y
				sta K.MLI.PARAMS+2,y

				iny
				tya					3 bytes, 24 bits!!!
				eor #3
				bne .81

				bcs .99					Offset out of range!			

.82				>MLICALL MLISETMARK
				bcc .9
				cmp #MLI.E.BEYEOF
				bne .9
				>MLICALL MLISETEOF
				bcc .82
.9				rts

.98				lda #E.BADARG
				.HS 2C					bit abs
.99				lda #E.FTB
*				sec
K.FSeek.RTS		rts
*/--------------------------------------
* # FEOF
* Test the end-of-file indicator for hFILE
* ## C
* `int feof(hFILE stream);`
* ## ASM
* **In:**
* `lda stream`
* `>SYSCALL feof`
* ## RETURN VALUE
*  CC : 
*  A = $ff EOF
*  A = 0 NOT EOF
*  CS :
*\--------------------------------------
K.FEOF			jsr PFT.CheckNodeA
				bcs K.FSeek.RTS

IO.EOF			lda (pFD)
				tax
				jmp (.1,x)
.1				.DA IO.EOF.REG
				.DA STDIO.IOERR			DIR
				.DA IO.EOF.CDEV
				.DA STDIO.IOERR			BDEV
				.DA STDIO.IOERR			LNK
				.DA STDIO.IOERR			DSOCK
				.DA IO.EOF.SSOCK
				.DA IO.EOF.PIPE
*/--------------------------------------
* # FTell
* Return the current value of the file-position indicator
* ## C
* `long ftell(hFILE stream);`
* ## ASM
* **In:**
* `lda stream`
* `>SYSCALL ftell`
* ## RETURN VALUE
* On stack (long)
*\--------------------------------------
K.FTell			jsr PFT.CheckNodeA
				bcs .9
				>MLICALL MLIGETMARK
				bcs .9

				lda #0
				>PUSHA

				ldy #2

.1				lda K.MLI.PARAMS+2,y
				>PUSHA
				dey
				bpl .1

.9				rts
*/--------------------------------------
* # Remove
* Remove a file or directory
* ## C
* int remove(const char *pathname);
* ## ASM
* **In:**
* `>PUSHW pathname`
* `>SYSCALL remove`
* ## RETURN VALUE
*\--------------------------------------
K.Remove		jsr PFT.CheckPath0
				bcs .9

				>MLICALL MLIDESTROY
.9				rts
*/--------------------------------------
* # Rename
* Rename a file
* ## C
* `int rename(const char *oldpath, const char *newpath);`
* ## ASM
* **In:**
* `>PUSHW oldpath`
* `>PUSHW newpath`
* `>SYSCALL rename`
* ## RETURN VALUE
*\--------------------------------------
K.Rename		jsr PFT.CheckPath2
				bcs .9

				>PULLW ZPPtr1

				ldy #0

.1				lda (ZPPtr1),y
				beq .8

				iny
				sta K.Buf256,y
				cpy #MLI.MAXPATH
				bne .1

.8				sty K.Buf256
				>LDYAI K.Buf256
				>STYA K.MLI.PARAMS+3
				>MLICALL MLIRENAME
				rts
.9				>RET 2
*--------------------------------------
* K.Buf256 = filepath
* X = hFD
*--------------------------------------
STDIO.NewHFile	sta .4+1				Store hFD
				ldx #1
.1				lda OF.Table.hFD-1,x
				beq .2

				inx
				cpx #K.OF.MAX+1
				bne .1

				lda #E.OOH
*				sec
				rts

.2				stx .3+1				Store hFILE

				lda (pFD)
				cmp #S.FD.T.CDEV
				beq .20

				cmp #S.FD.T.BDEV
				bne .21

.20				lda #0					No hPath for DEV
				bra .3

.21				>LDYAI K.buf256
				ldx #SYS.strdup
				jsr K.SYSCALL2
				bcs .9

				txa
.3				ldx #$ff				SELF MODIFIED
				sta OF.Table.hPath-1,x
.4				lda #$ff				SELF MODIFIED			
				sta OF.Table.hFD-1,x
				txa						hFILE

				clc
.9				rts
*--------------------------------------
MAN
SAVE USR/SRC/SYS/KERNEL.S.STDIO
LOAD USR/SRC/SYS/KERNEL.S
ASM
