
* Maxon C++ Library:
* Modul "buffers"
* Jens Gelhar 19.03.93, 20.02.94

	xdef	_setvbuf,setvbuf__P06streamPciUi
	xdef	_setbuf,setbuf__P06streamPc
	xdef	_fflush,fflush__P06stream
	xdef	_EXIT_2_Flush_Buffers_Yes_that_must_be

	xref	_DosBase,__Readfile__NoBuf,__Writefile__NoBuf
	xref	_std__err,_std__out
	xref	___Filelist

ExecBase	= 4

AllocMem	= -198
FreeMem		= -210

Seek		= -66

LF		= 10

str_mode	= 6
str_error	= 7
str_bufptr	= 8

buf_size	= 4
buf_fill	= 6
buf_pos		= 8
buf_mode	= 10
buf_own		= 11
buf_read	= 12
buf_write	= 16
buf_flush	= 20
buf_close	= 24
buf_buf		= 28
buf_SizeOf	= 32

_setbuf:
setbuf__P06streamPc:
	move.l d0,-(a7)
	move.l #200,-(a7)
	move.l #1,-(a7)
	move.l 3*4+4+4(a7),-(a7)
	move.l 3*4+4+4(a7),-(a7)
	bsr.b	setvbuf__P06streamPciUi
	lea 4*4(a7),a7
	move.l (a7)+,d0
	rts

_setvbuf:
setvbuf__P06streamPciUi:	; Parameter: 0 stream*, 4 char*, 8 mode, 12 size
	movem.l d1/a0/a1/a6,-(a7)
	tst.l 20(a7)
	beq svbOK               ; File #0
	tst.l 20+8(a7)
	beq svbOK               ; _IONBF
	move.l 20+12(a7),d0
	beq svbOK               ; leerer Buffer
	cmp.l #$FFFF,d0
	bls.b svbcs
	move.w #$FFFF,20+12+2(a7)       ; Maximalgröße 0xfff
svbcs:	move.l 20(a7),a0
	tst.l str_bufptr(a0)
	beq.b	svbOldBuf
	; schon Puffer gesetzt: wegschmeißen!
	movem.l d0/a0,-(a7)
	move.l str_bufptr(a0),a0
	move.l buf_close(a0),a6
	jsr (a6)
	movem.l (a7)+,d0/a0
svbOldBuf:
	move.l 20+4(a7),d0
	bne.b svb1              ; Speicherbereich angegeben?
	move.w 20+12+2(a7),d0
	moveq #0,d1
	move.l ExecBase.w,a6
	jsr AllocMem(a6)
	tst.l d0
	beq svbErr
svb1:	; Speicher d0 verwenden:
	move.l d0,-(a7)
	moveq #buf_SizeOf,d0
	move.l #$10000,d1
	move.l ExecBase.w,a6
	jsr AllocMem(a6)        ; buf-Struct einrichten
	move.l (a7)+,d1
	tst.l d0
	beq.b svbErr
	move.l d0,a1
	move.l d1,buf_buf(a1)
	move.l 20(a7),a0
	move.l a0,(a1)          ; Rückverweis auf Stream
	move.l a1,str_bufptr(a0)
	move.w 20+12+2(a7),buf_size(a1)
	tst.l 20+4(a7)
	bne.b svb2              ; Buffer nachher wieder freigeben?
	move.b #1,buf_own(a1)
svb2:
	cmp.b #1,str_mode(a0)
	beq.b svbRead
	; Schreibpuffer:
	lea WriteFlush(pc),a0
	move.l a0,buf_flush(a1)
	move.b #1,buf_mode(a1)
	tst.l 20+8(a7)
	bpl.b svb3
	move.b #2,buf_mode(a1)
	bra.b svb3
svbRead:	; Lesepuffer:
	move.b #-1,buf_mode(a1)
	lea ReadFlush(pc),a0
	move.l a0,buf_flush(a1)
svb3:	; gemeinsame Funktionen:
	lea ReadBuffer(pc),a0
	move.l a0,buf_read(a1)
	lea WriteBuffer(pc),a0
	move.l a0,buf_write(a1)
	lea CloseBuffer(pc),a0
	move.l a0,buf_close(a1)

svbOK:	moveq #0,d0
svbRet:	movem.l (a7)+,d1/a0/a1/a6
	rts
svbErr:	move.l #1002,d0
	bra.b svbRet

CloseBuffer:	; Buffer *a0 löschen
	tst.b buf_mode(a0)
	beq.b clb0
	bmi.b clb1
	; bei Schreibpuffer noch FLUSH machen
	move.l a0,-(a7)
	bsr WriteFlush
	move.l (a7)+,a0
clb0:	tst.b buf_own(a0)
	beq.b clb1
	; Buffer selbst löschen:
	moveq #0,d0
	move.w buf_size(a0),d0
	move.l buf_buf(a0),a1
	move.l ExecBase.w,a6
	move.l a0,-(a7)
	jsr FreeMem(a6)
	move.l (a7)+,a0
clb1:	; Bufferstruct löschen
	move.l (a0),a1          ; Rückverweis auf stream
	clr.l str_bufptr(a1)    ; Buffer austragen
	move.l ExecBase.w,a6
	move.l a0,a1
	moveq #buf_SizeOf,d0
	jmp FreeMem(a6)

ReadBuffer:	; Buffer *a0, void *d2, size_t d3, Returncode = gelesene Anzahl
	tst.b buf_mode(a0)
	bpl.b rbWrite
	exg d2,a1
	moveq #0,d0
rb0:	tst.l d3
	beq.b rbEnd
	moveq #0,d1
	move.w buf_fill(a0),d1
	sub.w buf_pos(a0),d1
	bhi.b rb1
	movem.l d0/d3/a1,-(a7)
	bsr.b FillBuffer
	move.l d0,d1
	movem.l (a7)+,d0/d3/a1
	tst.l d1
	beq.b rbEnd       ; Dateiende erreicht
rb1:	; noch d1 Zeichen im Puffer:
	cmp.l d3,d1
	bls.b rb2
	move.l d3,d1            ; Pufferinhalt > zu lesende Daten?
rb2:	; d1 > 0 Daten übertragen:
	move.l a2,-(a7)
	add.l d1,d0
	sub.l d1,d3
	move.w buf_pos(a0),a2
	add.l buf_buf(a0),a2
	add.w d1,buf_pos(a0)
rbCopy:	move.b (a2)+,(a1)+
	subq.w #1,d1
	bne.b rbCopy
	move.l (a7)+,a2
	; fertig?
	tst.l d3
	bne.b rb0
rbEnd:	exg d2,a1
	rts
rbWrite:	; Schreibpuffer, also "flush" und dann normal lesen
	movem.l d2/d3/a0,-(a7)
	bsr WriteFlush
	movem.l (a7)+,d2/d3/a0
	move.l (a0),a0
	jmp __Readfile__NoBuf

FillBuffer:	; a0 auffüllen, gelesene Zeichen nach d0
	move.l buf_buf(a0),d2
	moveq #0,d3
	move.w buf_size(a0),d3
	move.l a0,-(a7)
	move.l (a0),a0
	jsr __Readfile__NoBuf
	move.l (a7)+,a0
	clr.w buf_pos(a0)
	move.w d0,buf_fill(a0)
	rts

WriteBuffer:	; Buffer *a0, void *d2, size_t d3, Ergebnis <> 0 bei Fehler
	tst.b buf_mode(a0)
	beq wbRead
	bmi wbRead
	exg d2,a1
	cmp.b #2,buf_mode(a0)
	bne.b wbFull
	; Zeilenpuffer:
	tst.l d3
	beq.b wbFull
	movem.l d3/a1,-(a7)
wb0:	; Schleife: auf LF testen
	cmp.b #LF,(a1)+
	beq.b wbLF
	subq.l #1,d3
	bne.b wb0
	; kein LF mehr gefunden:
	movem.l (a7)+,a1/d3
	bra.b wbFull
wbLF:	; Zeilenende gefunden:
	move.l a1,d0
	movem.l (a7)+,a1/d3
	sub.l a1,d0     ; d0 von d3 Zeichen schreiben
	exg d3,d0
	move.l a1,-(a7)
	add.l d3,(a7)
	sub.l d3,d0
	move.l d0,-(a7)
	move.l a0,-(a7)
	bsr.b wbFull            ; bis einschl. Zeilenende voll ausgeben
	move.l (a7),a0
	bsr.b WriteFlush
	move.l (a7)+,a0
	move.l (a7)+,d3
	move.l (a7)+,d2
	tst.l d0
	beq.b WriteBuffer       ; und Rest ausgeben
	rts

wbFull:	; Vollgepufferte Ausgabe
	tst.l d3
	beq.b wbRet
wbLoop:	moveq #0,d0
	move.w buf_size(a0),d0
	sub.w buf_pos(a0),d0
	bhi.b wb1
	movem.l d3/a1,-(a7)
	bsr.b WriteFlush
	movem.l (a7)+,d3/a1
	tst.w d0
	bne.b wbRet
	moveq #0,d0
	move.w buf_size(a0),d0
wb1:	; Puffer hat noch Platz für d0.l Bytes
	cmp.l d0,d3
	bhs.b wb2
	move.l d3,d0
wb2:	; d0.l > 0 Bytes übertragen:
	move.l a2,-(a7)
	move.w buf_pos(a0),a2
	add.l	buf_buf(a0),a2
	add.w	d0,buf_pos(a0)
	sub.l	d0,d3
wb3:	move.b	(a1)+,(a2)+
	subq.w	#1,d0
	bne.b	wb3
	move.l	(a7)+,a2
	tst.l	d3
	bne.b	wbLoop
	moveq	#0,d0
wbRet:	exg	d2,a1
	rts
wbRead:	; Lesepuffer, also normal Schreiben:
	movem.l	a0/d2/d3,-(a7)
	bsr.b	ReadFlush
	movem.l	(a7)+,a0/a2/a3
	jmp	__Writefile__NoBuf

WriteFlush:	; Buffer *a0 wegschreiben, d0<>0 bei Fehler
	move.l a0,-(a7)
	move.l buf_buf(a0),d2
	moveq #0,d3
	move.w buf_pos(a0),d3
	move.l (a0),a0
	jsr __Writefile__NoBuf
	move.l (a7)+,a0
	clr.w buf_pos(a0)
	rts

ReadFlush:	; Buffer *a0 (Daten invalidieren, mit Seek zurückgehen)
	move.w	buf_pos(a0),d2
	sub.w	buf_fill(a0),d2
	bhs.b	rf1
	ext.l	d2
	moveq	#0,d3		; Offset_Current
	clr.w	buf_fill(a0)
	clr.w	buf_pos(a0)	; Inhalt vergessen
	move.l	_DosBase,a6
	move.l	(a0),a0
	clr.b	str_error(a0)
	move.l	(a0),d1
	beq.b	rf1
	jsr	Seek(a6)
rf1:	rts

_EXIT_2_Flush_Buffers_Yes_that_must_be:
	clr.l	-(a7)
	bsr.b	fflush__P06stream
	addq.l	#4,a7
	rts

_fflush:
fflush__P06stream:	; Parameter: FILE *
	tst.l 4(a7)
	bne.b	flsub
	; Alle offenen Files:
	move.l a0,-(a7)
	clr.l -(a7)
	move.l ___Filelist,a0
flLoop:	cmp.l #0,a0
	beq.b	flEnd
	move.l (a0),-(a7)
	pea 4(a0)
	bsr.b	flsub
	addq.l #4,a7
	move.l (a7)+,a0
	or.l d0,(a7)            ; Fehler summieren...
	bra.b flLoop
flEnd:	pea _std__err
	bsr.b flsub
	move.l #_std__out,(a7)
	bsr.b flsub
	addq.l #4,a7
	or.l (a7)+,d0           ; Fehlercode
	move.l (a7)+,a0
	rts

flsub:	; File 4(a7) <> 0
	moveq #0,d0
	move.l a0,-(a7)
	move.l 8(a7),a0
	tst.l str_bufptr(a0)
	beq.b flok
	move.l str_bufptr(a0),a0
	tst.b buf_mode(a0)
	beq.b flok
	bmi.b flread
	; Schreibpuffer:
	movem.l d1-d3/a1/a6,-(a7)
	move.l buf_flush(a0),a6
	jsr (a6)
	movem.l (a7)+,d1-d3/a1/a6
	tst.l d0
	beq.b flok
	bra.b flerr
flread:	; Lesepuffer:
	movem.l	d1-d3/a1/a6,-(a7)
	move.l	buf_flush(a0),a6
	jsr	(a6)
	movem.l	(a7)+,d1-d3/a1/a6
	moveq	#0,d0
	bra.b	flok
flerr:	moveq	#-1,d0
flok:	move.l	(a7)+,a0
	rts

	end
