
* Himpelsoft C++ Project:
* Library-Modul "scanf"
* Jens Gelhar 06.11.91, 18.06.94, 03.12.94, 15.12.94

	xdef	_scanf,scanf__PCce
	xdef	_fscanf,fscanf__P06streamPCce
	xdef	_sscanf,sscanf__PCcPCce

	xref	lib_double2float
	xref	_std__in,fgetc__P06stream,ungetc__iP06stream
	xref	strtovl__PCcPPci,strtouvl__PCcPPci,strtod__PCcPPc

_sscanf:
sscanf__PCcPCce:
	movem.l	d2-d7/a2-a6,-(a7)
	move.l	11*4+4(a7),a6		; Inputstring
	move.l	11*4+8(a7),a1		; Formatstring
	lea	11*4+12(a7),a2		; Parameter
	sub.l	a0,a0
	bra.b	schtjampf

_scanf:
scanf__PCce:
	movem.l	d2-d7/a2-a6,-(a7)
	lea	_std__in,a0
	move.l	11*4+4(a7),a1		; Formatstring
	lea	11*4+8(a7),a2		; Parameter
	bra.b	schtjampf

_fscanf:
fscanf__P06streamPCce:
	movem.l	d2-d7/a2-a6,-(a7)
	move.l	11*4+4(a7),a0		; Stream
	move.l	11*4+8(a7),a1		; Formatstring
	lea	11*4+12(a7),a2		; Parameter
schtjampf: ; Einsprung
	clr.l -(a7)             ; Return-Value für d0
	moveq #-1,d7            ; Zeichenzähler
	bsr Get
	tst.l d0
	bpl.b Loop
	move.l d0,(a7)
	bra End
Loop	; Hauptschleife (erstes Zeichen schon in d0)
	bsr OverreadFormat
	tst.b d1
	beq End
	cmp.b #'%',d1
	beq.b Prozent
Expect	; Zeichen vergleichen:
	bsr Overread
	cmp.b d0,d1
	bne ForgetLine              ; paßt nicht!
	bsr Get
	bra.b Loop
Prozent	move.b (a1)+,d1
	cmp.b #'*',d1
	bne.b noDummy
	sub.l a3,a3
	move.b (a1)+,d1
	bra.b Dummy
noDummy	move.l (a2)+,a3         ; Zielvector
Dummy	move.w #$7FFF,d6            ; Feldbreite
	cmp.b #'0',d1
	blo.b Arg
	cmp.b #'9',d1
	bhi.b Arg
	moveq #0,d6
	move.b d1,d6
Feldbr	sub.w #'0',d6
	moveq #0,d1
	move.b (a1)+,d1
	cmp.b #'0',d1
	blo.b Arg
	cmp.b #'9',d1
	bhi.b Arg
	mulu #10,d6
	add.w d1,d6
	bra.b Feldbr
Arg	and.w #$FF,d1
	cmp.b #'h',d1
	beq.b Laenge
	cmp.b #'l',d1
	beq.b Laenge
	cmp.b #'L',d1
	bne.b Scan
Laenge	asl.w #8,d1
	move.b (a1)+,d1
Scan	; Scan(doppel)code in d1.w:
	cmp.w #'s',d1
	beq String
	cmp.w #'c',d1
	beq Char
	cmp.w #'[',d1
	beq.b Pattern
	cmp.w #'%',d1
	beq GetProzent
	cmp.b #'n',d1
	beq Number
	; numerisch: d6 maximal Puffergröße
	cmp.w #StkBuf-4,d6
	bls.b scn1
	moveq #StkBuf-4,d6
scn1	move.w d1,d2
	cmp.b #'d',d1
	beq Dez
	cmp.b #'i',d1
	beq Int
	cmp.b #'x',d1
	beq Hex
	cmp.b #'p',d1
	beq Hex
	cmp.b #'o',d1
	beq Oct
	cmp.b #'e',d1
	beq Float
	cmp.b #'f',d1
	beq Float
	cmp.b #'g',d1
	beq Float
	; Formatfehler:
	bra End

Pattern:
	move.l a1,a4    ; Pattern-Anfang
	tst.b (a1)
	beq.b pat2
pat1	addq.l #1,a1
	tst.b (a1)
	beq.b pat2
	cmp.b #']',(a1)
	bne.b pat1
	move.l a1,d4
	addq.l #1,a1    ; Klammer am Ende nicht akzeptieren
	bra.b pat3
pat2	; Pattern von a4 bis a1:
	move.l a1,d4
pat3	sub.l a4,d4     ; Anfang a4, Länge d4
	addq.l #1,(a7)
	tst.w d6
	beq.b patEnd
patLoop	; d0 in Pattern?
	move.l a4,a5
	move.w d4,d5
	beq.b patEnd
	cmp.b #'^',(a4)
	bne.b patCheck
	addq.l #1,a5
	subq.w #1,d5
	beq.b patNein
patCheck cmp.b (a5)+,d0
	beq.b patJa
	cmp.b #'-',(a5)
	bne.b patNext
	cmp.w #3,d5
	blt.b patNext
	; Minus und nicht am Ende:
	subq.w #2,d5
	addq.l #1,a5
	cmp.b (a5)+,d0
	bhi.b patNext
	cmp.b -3(a5),d0
	bhs.b patJa
patNext	; weitersuchen:
	subq.w #1,d5
	bne.b patCheck
patNein	; nicht im Pattern:
	cmp.b #'^',(a4)
	bne.b patEnd
	bra.b patOK
patJa	; im Pattern:
	cmp.b #'^',(a4)
	beq.b patEnd
patOK	; Zeichen paßt
	move.l a3,d1
	beq.b patPut
	move.b d0,(a3)+         ; Zeichen in String schreiben
patPut	bsr Get
	tst.l d0
	bmi.b patEnd
	subq.w #1,d6
	bne.b patLoop
patEnd	move.l a3,d1
	beq Loop
	clr.b (a3)
	bra Loop

String:
	bsr OverreadLN
	cmp.b #10,d0
	bne.b s0
	bsr Get                 ; höchstens ein LF akzeptieren
	bsr OverreadLN
s0	tst.l d0
	bmi Loop
	addq.l #1,(a7)
	cmp.b #10,d0
	bne.b sLoop
	move.l a3,d1
	beq Loop
	clr.b (a3)
	bra Loop
sLoop	tst.w d6
	beq Loop
	move.l a3,d1
	beq.b s1
	move.b d0,(a3)+
	clr.b (a3)
s1	bsr Get
	tst.l d0
	bmi Loop
	cmp.b #' ',d0
	bls Loop
	subq.w #1,d6
	bra.b sLoop

Char:	tst.l d0
	bmi Loop
	addq.l #1,(a7)
	cmp.w #$7FFF,d6
	blo.b cloop
	moveq #1,d6
cloop	tst.w d6
	beq Loop
	move.l a3,d2
	beq.b ch1
	move.b d0,(a3)+
ch1	bsr Get
	tst.l d0
	bmi Loop
	cmp.b #' ',d0
	bls Loop
	subq.w #1,d6
	bra.b cloop

StkBuf	= 80

Dez:	bsr Overread
	lea -StkBuf(a7),a7
	cmp.w #StkBuf-4,d6
	bls.b dz1
	moveq #StkBuf-4,d6
dz1	move.l a7,a4
	bsr Sign
	bsr DigitSequence
	moveq #10,d4
Convert	; String a7 bis a4 mit Basis d4
	exg	d0,d4
	clr.b	(a4)
	move.b	(a7),d1
	beq.b	dzErr
	move.l	a0,-(a7)
	move.l	d0,-(a7)
	clr.l	-(a7)
	pea	12(a7)
	cmp.b	#'-',d1
	beq.b	dzSig
	cmp.b	#'+',d1
	beq.b	dzSig
	jsr	strtouvl__PCcPPci
	bra.b	dzUnSig
dzSig	jsr	strtovl__PCcPPci
dzUnSig	lea	12(a7),a7
	move.l	(a7)+,a0
	lea	StkBuf(a7),a7
	addq.l #1,(a7)
	lsr.w #8,d2
	cmp.w #'L',d2
	beq.b PutDouble
	cmp.w #'h',d2
	beq.b PutWord
Put	move.l a3,d2
	beq.b GoOn
	move.l d0,(a3)
GoOn	move.l d4,d0            ; gemerktes Zeichen
	bra Loop

PutDouble:
	move.l a3,d2
	beq Loop
	movem.l d0/d1,(a3)
	bra.b GoOn

PutWord:
	move.l a3,d2
	beq Loop
	move.w d0,(a3)
	bra.b GoOn

dzErr	lea StkBuf(a7),a7
ForgetLine:	; Fehler: Rest der Zeile überlesen
	tst.l d0
	bmi End
	tst.b d0
	beq End
	cmp.b #10,d0
	beq End
	bsr Get
	bra.b ForgetLine


Int:	bsr Overread
	lea -StkBuf(a7),a7
	move.l a7,a4
	bsr Sign
	cmp.b #'0',d0
	bne.b int2
	bsr Accept
	cmp.b #'x',d0
	beq.b inHx
	cmp.b #'X',d0
	beq.b inHx
	bra.b ocLoop
int2	bsr DigitSequence
	moveq #10,d4
	bra Convert

Hex:	bsr Overread
	lea -StkBuf(a7),a7
	move.l a7,a4
	bsr Sign
	cmp.b #'0',d0
	bne.b hx2
	bsr Accept
	cmp.b #'x',d0           ; "x" unterschlagen
	beq.b inHx
	cmp.b #'X',d0
	bne.b hx2
inHx	subq.w #1,d6
	bsr Get
	bra.b hx2
hxLoop	bsr Accept
hx2	cmp.b #'0',d0
	blo.b hx3
	cmp.b #'9',d0
	bls.b hxLoop
	cmp.b #'A',d0
	blo.b hx3
	cmp.b #'F',d0
	bls.b hxLoop
	cmp.b #'a',d0
	blo.b hx3
	cmp.b #'f',d0
	bls.b hxLoop
hx3	moveq #16,d4
	bra Convert

Oct:	bsr Overread
	lea -StkBuf(a7),a7
	move.l a7,a4
	bsr Sign
ocLoop	cmp.b #'0',d0
	blo.b oc1
	cmp.b #'7',d0
	bhi.b oc1
	bsr Accept
	bra.b ocLoop
oc1	moveq #8,d4
	bra Convert

Float:	bsr Overread
	lea -StkBuf(a7),a7
	move.l a7,a4
	clr.w (a7)
	bsr.b Sign
	bsr DigitSequence
	bsr.b	Punkt
	bsr	DigitSequence
	tst.b	(a7)
	beq dzErr               ; ungültiger Anfang
	cmp.b #'e',d0
	beq.b flExp
	cmp.b #'E',d0
	bne.b flAcc
flExp	bsr.b Accept
	move.l a4,d1
	bsr.b Sign
	bsr.b DigitSequence
	cmp.l a4,d1
	bne.b flAcc
	; hinter "e" kam nichts mehr:
	move.l d0,-(a7)
	move.b -(a4),d0
	bsr Unget
	move.l (a7)+,d0
flAcc	clr.b (a4)
	tst.b (a7)
	beq dzErr
	move.l d0,d4
	move.l	a0,-(a7)
	clr.l	-(a7)
	pea	8(a7)
	jsr	strtod__PCcPPc
	addq.l	#8,a7
	move.l	(a7)+,a0
	lea	StkBuf(a7),a7
	addq.l	#1,(a7)
	lsr.w #8,d2
	tst.b d2
	bne PutDouble
	jsr lib_double2float
	bra Put         ; float

Punkt:	; Dezimalpunkt akzeptieren
	cmp.b #'.',d0
	beq.b Accept
	bra.b ret

Sign:	; +,- akzeptieren
	cmp.b #'+',d0
	beq.b Accept
	cmp.b #'-',d0
	bne.b ret
Accept:	tst.w d6
	beq.b sgEnd
	bmi.b sgEnd
	subq.w #1,d6
	move.b d0,(a4)+
	bra Get
sgEnd	moveq #-1,d0
ret	rts

DigitSequence:
	cmp.b #'0',d0
	blo.b ret
	cmp.b #'9',d0
	bhi.b ret
	tst.w d6
	beq.b ret
	subq.w #1,d6
	move.b d0,(a4)+
	bsr Get
	bra.b DigitSequence

Number:	; Anzahl zurückgeben
	move.l a3,d2
	beq Loop
	cmp.w #'hn',d1
	beq.b numW
	move.l d7,(a3)+
	cmp.w #'ln',d1
	bne Loop
	clr.l (a3)
	bra Loop
numW	move.w d7,(a3)
	bra Loop

GetProzent:	; "%" akzeptieren
	moveq #'%',d1
	move.l a3,d1
	beq Expect
	subq.l #4,a2    ; Pointer brauchen wir nicht
	bra Expect

End:	cmp.b #10,d0
	beq.b end1        ; "LF" nicht zurückstellen
	bsr.b Unget
end1	movem.l (a7)+,d0/d2-d7/a2-a6
	rts

OverreadLN:	; In Stream Zwischenraum überlesen, aber nicht LF
	cmp.b #' ',d0
	beq.b ovl1
	cmp.b #9,d0
	beq.b ovl1
	cmp.b #13,d0
	beq.b ovl1
	rts
ovl1	bsr.b Get
	bra.b OverreadLN

Overread:	; In Stream Zwischenraum überlesen
	bsr.b OverreadLN
	cmp.b #10,d0
	bne ret
	bsr.b Get
	bra.b Overread

OverreadFormat:	; im Formatstring Zwischenraum überlesen, Zeichen nach d1
	move.b (a1)+,d1
	beq.b ovr0
	cmp.b #' ',d1
	beq.b OverreadFormat
	cmp.b #9,d1
	beq.b OverreadFormat
	cmp.b #10,d1
	beq.b OverreadFormat
	cmp.b #13,d1
	beq.b OverreadFormat
ovr0	rts

Get:	; Zeichen nach d0.l und d7 incrementieren, oder -1
	move.l	a0,-(a7)
	beq.b	gtChar		; a0=0, also sscanf
	jsr	fgetc__P06stream
	move.l	(a7)+,a0
	tst.l	d0
	bmi.b	gt1
gt0	addq.l	#1,d7
gt1	rts
gtChar	addq.l	#4,a7
	moveq	#0,d0
	move.b	(a6)+,d0
	bne.b	gt0
	moveq	#-1,d0
	rts

Unget:	; d0 zurückstellen, falls nicht -1
	tst.l	d0
	bmi.b	ung1
	move.l	a0,-(a7)
	beq.b	ungChar
	move.l	d0,-(a7)
	jsr	ungetc__iP06stream
	addq.l	#4,a7
	move.l	(a7)+,a0
	subq.l	#1,d7
ung1	rts
ungChar	addq.l	#4,a7
	subq.l	#1,a6
	subq.l	#1,d7
	rts

	end
