Source file: /~heha/vt/viewers/vt080.zip/src/RESIDENT.ASM

;Alles Residente zum Videotext...
DATASEG
extrn HInstance:word
CODESEG

proc Assert_Segregs
	pushf
	push	ax bx
	 mov	bx,[HInstance]
	 or	bl,7
	 mov	ax,ds
	 sub	ax,bx
	 jnz	@@err
	 mov	ax,es
	 sub	ax,bx
	 jnz	@@err
	 mov	ax,ss
	 sub	ax,bx
	 jz	@@okay
@@err:	 int	3
@@okay:	pop	bx ax
	popf
	ret
endp

proc VPollInit	;(resident)
	; CY=1: Fehler:
	; - Kein Speicher
	; - Dekoder-Semaphorendatei der gefundenen Adresse wird bereits
	;   benutzt (Nach Löschung derselben taucht sie wieder auf)
	int	3
	cld
	btst	[TheSw],bit 7	;Nicht mehrfach einschalten!
	jnz	@@e
	mov	di,ofs CurVTHandle
	mov	cx,(ReqE-CurVTHandle)/2 ;Alles hübsch aufräumen
	xor	ax,ax		;löscht auch CurVT! Gründlich!
	btst	[ctrl0],bit 5
	rep	stosw		;Gründlich "initialisieren"
	jz	@@1a
	bset	[ctrl0],bit 5
@@1a:	mov	[CurIdx],ax	;Auch Indizes löschen! (wg. Standardausgabe)
	mov	[ringzaehler],ofs Req1	;Startwert
	call	CreateSemaphorFile
				;rigoros überschreiben
	jc	@@e		;Fehler: Pfad nicht gefunden! Schalter bleibt aus.
	xor	bh,bh
	mov	dx,7ffh		;Seltene Seite
	mov	cx,8000h
@@9:	call	CalcAcqPtr
	mov	[acq.Zust],ruhend
	cmp	bh,3
	jnz	@@9a
	mov	[acq.Zust],spezial
	mov	dx,cx		;nach *.* suchen!!!
@@9a:	call	ProgAcq
	inc	bh
	and	bh,3
	jnz	@@9
;Display Chapter =0 einstellen !!
	mov	si,ofs dc$	;Dahin kommt die Uhrzeit!
	call	SStrI2C
	call	PagePredict_Init ;Prädiktor-Tabelle löschen
	mov	[MyTimer],0	;Init!
;	call	TimerInit
	AcqOn		;Akquisitoren an
	bset	[TheSw],bit 7
@@e:	ret
	endp

proc VPollRun	;GANZ FRÜH Datum der Semaphorendatei prüfen
	cld			;Klare Verhältnisse bitte!
	btst	[TheSw],bit 7	;Darf nur laufen, wenn der Big Switch ON
	jz	@@f
	call	UpdateAllTimer	;liefert in DX die vergangene Zeit
	add	[LoadTick],dx
	cmp	[LoadTick],18	;Aller einer Sekunde testen! (reicht zu!)
	jc	@@51
	mov	[LoadTick],0
	call	LoadSemaphorFile
	;NOCH FRÜHER Dispatcher
	;Nun ARRIVED testen, aber nur bei "SUCHENDEN" Akquisitoren
@@51:	call	CheckArrived
	;..
	;Okay, alle Requests (wenn möglich) verarztet
	;Für Arbeitslose neuen Suchbefehl geben
	;Bei Bedarf Semaphorendatei speichern
@@5:
	cmp	[MyTimer],0
;	call	GetTimer
;	cmp	[OldTimer],ax
	jnz	@@6
	btst	[ctrl0],bit 9	;Trailing Garbage?
	jz	@@7
	call	VTFile_Garb_Run
	jr	@@5
@@7:
	btst	[ctrl0],bit 10	;Trailing Load?
	jz	@@6
	call	VTFile_Load_Run
	jr	@@5
@@6:	mov	ax,[ctrl0]
	xor	ax,[OldCtrls]
	inc	ax
	jz	@@e
	call	CreateSemaphorFile
@@e:	call	CheckForFullArrived
@@f:	ret
endp

proc VpollDone	;(resident?)	;beim Beenden des Programms gerufen ...
	;Semaphorendatei löschen
	cld
	btst	[TheSw],bit 7	;Nicht mehrfach ausschalten!
	jz	@@e
	bres	[TheSw],bit 7
		AcqOff		;Akquisitoren aus
		; (so selten wie ein privilegierter Befehl!)
	mov	dx,ofs SemaFile
	DOS	41h		;löschen
	call	VTFile_Close
@@e:
	ret
	endp

;####################################################################
	_STRCPY

proc CheckForFullArrived
	xor	ax,ax
	cmp	[Acq0.Zust],al
	jnz	@@e1
	cmp	[Acq1.Zust],al
	jnz	@@e1
	cmp	[Acq2.Zust],al
	jnz	@@e1		;Mindestens 1 Acq. beschäftigt?
	btst	[ctrl0],bit 11	;Schon gelöscht?
	jz	@@e
	bres	[ctrl0],bit 11	;bestätigen: Alles fertig!
	mov	[pTime],18*2	;2 Sekunden Verzögerung!
	jr	@@e
@@e1:	bset	[ctrl0],bit 11
@@e:	ret
	endp

proc ResetSeeks
	mov	cx,(ReqE-Req1)/2
	mov	di,ofs Req1
	xor	ax,ax
	mov	bx,8000h	;gleich mal Unterseiten-NoCare-Bits setzen
@@l:	stosw
	xchg	ax,bx
	loop	@@l
	ret
	endp

ifdef resident
proc Broadcast c
 uses bx,cx,dx,si,di,ds,es	;Alles retten was zu retten ist!
	btst	[ctrl1],bit 1	;Boadcast allowed?
	jz	@@e
	mov	ah,[MUXI]
	MUX
@@e:	ret
endp
else
Broadcast: ret
endif

;####################################################################

InitGetRAM:
	;Gibt Standardsequenz aus, um dann vom RAM zu lesen
	;PE: AX=Zeile+256*Spalte (Adresse)
	push	si
	 mov	si,ofs igr$
	 mov	[si+2],bh
	 mov	[si+3],ax
	 call	SStrI2C		;Stringausgabe
	pop	si
	ret

DATASEG
label HoldOneAcq$ byte
	dps	2,0,0	;erste Null wird modifiziert
CODESEG
proc HoldOneAcq
;PE: BH=Akquisitor(0..3), der gestoppt werden soll
	push	si ax
	 mov	al,bh
	 shl	al,4
	 or	al,40h
	 mov	si,ofs HoldOneAcq$
	 mov	[si+2],al
	 call	SStrI2C
	pop	ax si
	ret
endp	

proc GetPage
	;Hole 1 Seite aus VTD-RAM nach Buf
	;PE: BH: Seitennummer
	;PA: [Buf] gefüllt mit Seite, NOCH KEINE Seiteninfos berechnen
	;VR:
	call	ReadHdr
	mov	ax,1		;Zeile 1
	call	InitGetRAM
	mov	cx,23*40	;Zeilen 1..23
	call	RI2C
	push	bx
	 add	bh,4
	 mov	ax,24
	 call	InitGetRAM
	pop	bx
	mov	cx,40		;Zeile 24 (muß extra gezogen werden...)
	call	RI2C
	mov	ax,25
	call	InitGetRAM
	mov	cx,24		;Zeile 25 (Rest)
	call	RI2C
	ret
	endp

proc LiesSeite
	call	GetPage		;liest Seite in Puffer
	call	ModifyPage	;patcht noch wichtige Daten hinein
				;und macht noch dieses und jenes (PA: CY!!)
	ret
	endp

;####################################################################
proc ReadHL	;evtl. Statuszeile einlesen, BH=Akquisitor
	cmp	[CurVT],0	;Name unbekannt?
	jz	@@3		;Wegen des Namens einlesen!
	btst	[ctrl0],bit 11	;Fertig eingelesen?
	jz	@@3		;ja, einen Senderwechsel erwarten
	btst	[ctrl0],bit 0	;Wegen eines User-Requests einlesen?
	jnz	@@e		;wenn nein, dann nix tun
@@3:	call	ReadHdr		;Zeile 0, Spalte 0
	call	CheckHL		;und testen
@@e:	ret
	endp

proc ReadHdr
	;liest Kopfzeile von [BH] und Uhrzeit von [0] ein
	;fest nach [Buf+8]
	mov	ax,8*256+0
	call	InitGetRAM
	mov	cx,24
	mov	si,ofs Buf+8
	call	RI2C
	push	bx
	 xor	bh,bh
	 mov	ax,32*256+0
	 call	InitGetRAM
	 mov	cx,8
	 call	RI2C
	pop	bx
	ret
	endp

proc CheckValidSubp
	btst	[ctrl0],bit 1	;Pseudoseiten erlaubt?
	jnz	@@e		;ja
	btst	[acq.Subp],bit 15 ;Sollte eine bestimmte Unterseite gesucht werden?
	jnz	@@e		;ja
	mov	ax,[acq.fSubPg]
	call	CheckPseudoSubPage
@@e:	ret
	endp

;####################################################################
proc CheckPBLF
	push	di
	 mov	ax,9*256+25	;Zeile 25, Spalte 9 (Statusinfo holen)
	 call	InitGetRAM
	 mov	cx,1		;Nur 1 Byte bitte!
	 call	RBufI2C
	pop	di
	test	[by Buf],20h	;Bit5 testen (PBLF)
	ret
	endp

DATASEG
gpi_scratch	dw	?
CODESEG
proc GetPageInf
	;PE: DI: Zeiger auf Akquisitorspiegel sowie BH=Acq-Nummer!
	;PA: DX: Seite, CX: Unterseite (ganz nebenbei)
	mov	ax,25		;Zeile 25, Spalte 0
	call	InitGetRAM
	mov	cx,9		;Spalte 0 bis 8 lesen
	call	RBufI2C
	mov	[gpi_scratch],bx
	push	bx
	 mov	si,ofs Buf
	 call	GetPageInfo	;[SI]->DX-CX-BX-AH
	 mov	[acq.fPage],dx	;Seite
	 mov	[acq.fSubPg],cx	;Unterseite
	 mov	[acq.fBits],bx	;Bits
	 mov	[acq.fHamE],ah	;Errors
	 pusha
	  call	PutGotPage
	 popa
	pop	bx
	ret
	endp

proc PutGotPage
	push	di
	 mov	di,ofs Buf
	 push	ax
	  mov	al,'!'		;Zeichen: Gefunden
	  stosb
	  mov	ax,dx
	  call	PutPageOrStar
	  mov	al,'/'
	  stosb
	  mov	ax,cx
	  call	PutSubPageOrStar
	  mov	al,'-'
	  stosb
	  mov	ax,bx
	  call	putHexAX	;C-Flags
	 pop	ax
	 mov	al,'E'
	 stosb
	 xchg	al,ah
	 call	putHexAL	;Errors
	 mov	al,0
	 stosb
	pop	di
	push	[gpi_scratch]	;Acq
	push	ds ofs Buf	;Msg
	push	1		;Auf neuer Zeile ausschreiben
	call	Message
	ret
endp

proc CheckArrived
	;testet jeden suchenden Aquisitor auf geglückten Empfang
	;und stellt Status auf "SOEBEN_GEFUNDEN".
	;Außerdem wird die gefundene Seite usw. vermerkt
	;VR: verwendet Universalpuffer BUF!!
	xor	bh,bh
@@1:	call	CalcAcqPtr
	mov	ax,[acq.Stat]
	cmp	al,ruhend
	jz	@@ruhend
	cmp	al,suchend
	jz	@@suchend
	cmp	al,wartend
	jz	@@wartend
	cmp	al,spezial
	jn	z,@@spezial
@@2a:	jmp	@@2		;Keine Aufgabe

@@toruhendf:
	inc	[Stats.Faults]
@@toruhend:
	bres	[ctrl1],bit 0	;Eine Seite könnte ja nun verfügbar sein!
	mov	[acq.Zust],ruhend
;### CASE zustand OF ###

@@ruhend:
	call	ReqDisp		;Request-Dispatcher suchen lassen
ifdef verbose
	jc	@@r2
else
	jc	@@2a
endif
	mov	[acq.Level],bl
	call	InitAcq
	mov	al,suchend
	jmp	@@2w
ifdef verbose
@@r2:
;DATASEG
;@@star	db	'*',0
;CODESEG
;	push	bx
;	push	ds ofs @@star
;	push	0
;	call	Message	;bei NonVerbose Tonausgabe für arbeitslosen Acq
	jr	@@2a
endif

@@suchend:
	call	CheckPBLF
	jnz	@@s1		;Die Nase sucht ja immer noch!
;Seite wurde gefunden, Headerdaten einlesen
	call	GetPageInf
	call	Barometer_Shift1 ;Stimmungsbarometer heben
	call	PagePredict_PutLast ;Als letzte gefundene Seite eintragen
				;(aber nur, wenn kein Untertitel!)
	call	CheckValidSubp	;Unterseite gültig?
	jc	@@toruhend
	mov	al,wartend
	jmp	@@2w		;Neuen Zustand eintragen und Zeit auf Null
@@s1:	;wenn immer noch gesucht wird
	mov	bl,[acq.Level]
	mov	ax,[acq.Zeit]
	cmp	ax,SuchSubTimeOut
	jnc	@@s2		;überschritten
	btst	[acq.SubP],bit 15 ;Unterseite?
	jz	@@2		;ja
	cmp	ax,SuchTimeOut
	jnc	@@s2
	cmp	bl,3
	jc	@@2		;nein, weitersuchen
	cmp	ax,SuchShortTimeOut
	jc	@@2		;keine Überschreitung. Weitersuchen
@@s2:	clc			;sicherheitshalber
	call	Barometer_Shift	;Stimmungsbarometer senken
	call	DelDisp
	jr	@@toruhend	;Einen neuen Job übernehmen!


@@wartend:
	cmp	[acq.Zeit],WarteTimeOut
	jc	@@2		;fertig für diesen Akquisitor!
	cmp	[MyTimer],2	;Nicht zuviel auf einmal machen!
	jnc	@@2		;Noch nicht lesen, erst beim nächsten Mal
	call	LiesSeite	;evtl. fragwürdige Kopfzeile!
	jn	c,@@toruhendf	;dann muß die Seite verworfen werden
	call	UpdDisp
	jmp	@@toruhend	;Neuer Job fällig!

@@spezial:
	call	CheckPBLF
	jnz	@@z1		;Die Nase sucht ja immer noch!
;Seite wurde gefunden, Headerdaten einlesen
	call	GetPageInf
	btst	[acq.fBits],bit 7 + bit 10 ;Kopfzeile oder alles unterdrückt?
	jnz	@@z4
	call	ReadHL
@@z4:	call	PagePredict_PutLast ;Als letzte gefundene Seite eintragen
				;aber nur wenn kein Untertitel!
	mov	dx,8000h
	mov	cx,dx
	call	ProgAcq
	jr	@@z2		;Neuen Zustand eintragen und Zeit auf Null
@@z1:	;wenn immer noch gesucht wird
	mov	ax,[acq.Zeit]
	cmp	ax,SuchSpezTimeOut
	jc	@@2		;nicht überschritten
	call	DecOtherTimers
	call	I2CStat
	xor	al,1		;oder auf 625 Zeilen (Europa?)
	btst	al,81h		;Videosignalqualität testen
	mov	ax,1500		;Tiefer Pieps: Kein Videotext!
	jz	@@z3
	mov	ax,4096		;Ganz tiefer Pieps: Kein Fernsehsignal!
@@z3:	call	Pieps
	mov	ah,81h
	call	Broadcast
@@z2:	mov	al,spezial
;	jr	@@2w

;### END CASE zustand ###

@@2w:	mov	[acq.Zust],al	;Ende mit neuem Zustand
	mov	[acq.Zeit],0
@@2:	inc	bh		;weiter mit altem Zustand
	and	bh,3
	JN	nz,@@1
	ret
endp CheckArrived
;####################################################################
;PagePredict=object
;bitfield:array[byte]of byte
;LastPut, LastGet: word;
;constructor init
;procedure put(DX:Videotextseite)
;procedure delete(DX:Videotextseite)
;function get:DX:Videotextseite
;function next:DX:Videotextseite
;####################################################################

proc DecOtherTimers c	;um AX, damit es nicht zu Löschungen kommt!
 uses di
	mov	di,ofs Acq0.Zeit
	mov	cx,3
@@l:	sub	[di],ax
	jnc	@@1
	mov	[wo di],0
@@1:	loop	@@l
	ret
endp
;####################################################################
;function GetPageInfo(SI:Pointer):DX/CX/BX/AH;external;
;proc GetPageInfo
	;hole aus [SI] (Abbild der Zeile 25) die Angaben über:
	;DX- Seite
	;CX- Unterseite
	;BX- C-Bits
	;AH- HamErrors
	;VR:AX,SI

;####################################################################
proc LoadSemaphorFile
	;Zeitstempel der Semaphorendatei prüfen und Datei
	;nur! bei Veränderung laden
	mov	dx,ofs DTA
	DOS	1Ah
	mov	dx,ofs SemaFile	;Zeiger auf Semaphorendatei
	xor	cx,cx		;Keine Attribute!
	DOS	4eh		;FindFirst, DTA sei gesetzt
	jc	CreateSemaphorFile
				;Nicht gefunden! - Dann Create!
	mov	cx,[wo DTA+16h]
	mov	dx,[wo DTA+18h]
	cmp	[OldTime],cx
	jnz	@@2
	cmp	[OldDate],dx
	jz	@@e		;Alles noch OK
@@2:	;Verschiedene Zeiten! - Datei-Abbild updaten
	mov	dx,ofs SemaFile	;Zeit updaten? beim Schließen erst.
	DOS	3d00h		;Datei zum Lesen öffnen
	jc	@@4		;Fehler
	xchg	bx,ax		;Handle
	mov	cx,Req0-CurVT
	mov	dx,ofs CurVT	;Requests Level 1
	DOS	3fh		;lesen
	jr	fClose
@@4:	;Fehler beim Öffnen ?!?
@@e:	ret
	endp

proc CreateSemaphorFile		;Schreib mal wieder ein paar Bytechen
	bres	[ctrl0],bit 8	;Request löschen (bei Zugriff woandershin)
	mov	ax,[wo ctrl0]
	not	ax
	mov	[OldCtrls],ax	;Bestätigung des Schreibvorgangs
	mov	dx,ofs SemaFile
	xor	cx,cx		;Keine besonderen Attribute
	DOS	3ch
	jc	@@e
	xchg	bx,ax
	mov	cx,Req0-CurVT
	mov	dx,ofs CurVT
	DOS	40h		;Bytes schreiben
	jc	fClose
	cmp	ax,cx		;Weniger geschrieben ist auch Fehler!
fClose:
	pushf
	 DOS	5700h		;Uhrzeit lesen
	 mov	[OldTime],cx
	 mov	[OldDate],dx
	 DOS	3eh		;schließen
	popf
@@e:	ret
	endp

;#####################################################################
proc ReqDisp	;RequestDispatcher
	;Gibt einem Akquisitor neue Arbeit
	;PE: BH: Akquisitor-Nr, DI: Zeiger auf ACQn
	;PA: DX/CX Neue Seite, BL: Privileg
	;    CY=1: Kann keinen neuen Job vergeben
	;TEMPORÄR ein Iterationszähler BL

	call	GetRequestedPage
	jnc	@@ex
;Nicht zu lange an der Tabelle herumsuchen lassen!
	cmp	[MyTimer],2	;maximal 1 Tick zulassen!
@@ex1:	cmc
	jc	@@ex		;und Tschüß! (wenn zuviel Zeit verstrichen)
	btst	[ctrl1],bit 0	;Lohnt sich die lange Suche überhaupt?
	jnz	@@ex1		;Raus mit CY=1: Vorerst keine Suche!
	mov	cx,8000h
	call	GetUniqPredPage
	mov	bl,0
	jc	@@ex		;wenn kein Tip aus dem Prädiktor
@@l:	call	CheckUpdateComplete
	jnc	@@e		;Okay zum Suchen
	call	GetUniqNextPage
	INCB	bl		;bis zu FF erhöhen, verändert Carry nicht
	jnc	@@l		;wenn der Prädiktor noch was hat...
	jr	@@ex
@@e:    ;BL nun Anzahl der Iterationen
	push	dx
	 call	Barometer_Get
	pop	dx
	MIN	al,8		;8=Obergrenze
	mov	ah,3		;Normaler Privileg
	cmp	bl,al
	jc	@@p2
	mov	ah,2		;Bei BL größer 8 oder Barometerstand
@@p2:
;ifdef Verbose
;	push	ax dx
;	 mov	al,bl		;TEMPORÄR
;	 call	ahex		;"" (Barometerstand?)
;	 mov	al,'#'		;""???
;	 call	ochr		;""
;	pop	dx ax
;endif
	mov	bl,ah		;Privileg hier 3 oder 2
	clc
@@ex:	ret
	endp

proc CheckUpdateComplete c
 uses bx,cx,dx,di
	;PE: DX: Seite
	;PA: CY=1, wenn sich die Suche nicht mehr lohnt:
	; - Eine Seite ohne Unterseiten wurde 2mal gleich eingelesen
	; - Zu mindestens einer Seite gibt es eine Unterseite >=100h
	; - Alle Unterseiten sind gelesen und zusammenhängend
	; - Bei verfügbarer maximaler Unterseite sind alle vorhanden
	; - Die Seite enthält Pseudotetraden und die Suche danach ist
	;   nicht erlaubt
	;    CY=0, wenn Suche empfohlen: (bl=3)
	; - Seite nicht vorhanden
	; - Unterseiten nicht zusammenhängend eingelesen
	; - Nur eine Unterseite 1 (es gibt ja mindestens zwei)
	; - Bei verfügbarer maximaler Unterseite fehlt etwas
	 btst	[ctrl0],bit 1	;Pseudoseiten ein?
	 jnz	@@p
	 mov	ax,dx
	 call	CheckPseudoPage	;dürfte eigentlich nicht so wichtig sein...
	 jn	c,@@e
@@p:	 mov	di,ofs Buf2
	 mov	cx,80h/2
	 xor	ax,ax
	 rep	stosw		;Buf2 leeren
	 mov	si,ofs Index
	 mov	cx,[CurIdx]
;in Buf2 die Unterseiten zu einer Seitennummer aufreihen lassen...
	 clc
	 jcxz	@@e		;NOT IN LIST suchen lassen!
	 xor	di,di		;Maximale Unterseiten-Nummer
@@l:	 lodsw
	 cmp	ax,dx		;Gesuchte Seite?
	 lodsw			;Unterseite
	 stc
	 jnz	@@2
	 bres	ax,bit 15 + bit 14 ;Infobits entfernen
	 push	ax
	  call	CheckPseudoSubPage
	 pop	ax
	 jc	@@2		;Nicht eintragen bei zu großen oder Pseudo-Seiten
	 MAX	di,ax		;DI:=Max(DI,AX)
	 mov	bx,ax
	 mov	al,[si-1]	;High-Teil Subpage (Interessant: Infobits!)
	 inc	al		;Bit0 setzen
	 mov	[Buf2+bx],al	;Suchstatus-Bits + Bit0: In Index enthalten
@@2:	 loop	@@l
;Aufreihung in Buf2 okay, nun Auswertung...
	 mov	al,[Buf2]	;Unterseite 0?
	 or	al,al		;nicht vorhanden?
	 jz	@@s		;ab zum Unterseiten-Check
	 mov	cl,al
	 btst	[ctrl0],bit 4
	 jnz	@@k
	 or	di,di		;Eine Unterseite?
	 jnz	@@k1		;ja, löschen
	 call	MSList_GetMS	;Unterseite vorausgesagt?
	 jc	@@k		;nein, weiterwurschteln
@@k1:	 xor	bx,bx
	 call	DeletePagesFromTo ;löscht nur UNGELESENE Seiten!
@@k:	 cmp	cl,80h		;Bit7 gesetzt? (2x korrekt gelesen?)
	 jr	@@r1		;Je nach Bit7 suchen (CY=0 wenn 0) oder nicht suchen!

@@s:	;MIT Unterseiten!!
	 call	MSList_GetMS
	 jc	@@w2
	 cmp	ax,di		;Mehr Seiten vorhanden als bei xx/yy angegeben?
	 jnc	@@w3		;(DI>AX) nein
	 push	ax		;Anzahl der VORHERGESAGTEN Seiten
	  xchg	bx,ax		;ja - Überschüssige Seiten löschen
	  call	DeletePagesFromTo ;löscht nur UNGELESENE Seiten (aus Datei)
	 pop	ax		;DIESE Unterseitenzahl für richtig halten!
@@w3:	 xchg	di,ax
	 jr	@@w1		;Nicht erst auf mind. 2 testen!
@@w2:
	 mov	ax,2		;AX=2
	 MAX	di,ax		;DI muß mindestens 2 sein!
@@w1:	 mov	ax,1		;AX=1, Schleifenparameter
@@l2:	 xchg	bx,ax
	 cmp	[Buf2+bx],40h	;Unterseite vorhanden UND (1x) eingelesen?
;(Ermessensfrage, wie GUT die Unterseiten gelesen werden sollen!)
;(Eine ZEILENWEISE Fehlerauswertung brächte hier die besten Ergebnisse.)
	 jc	@@r1		;nein - suchen lassen!
	 xchg	ax,bx
	 add	al,1
	 daa
	 cmp	di,ax		;End-Unterseite erreicht?
	 jnc	@@l2
	 clc			;d.h. Carry setzen: alle Unterseiten sind da!
@@r1:	 cmc
@@e:	ret
endp CheckUpdateComplete

proc DeletePagesFromTo
	;PE: BX=Startindex, DI=Stopindex
	;Aber nur solche Seiten löschen, die noch nicht gefunden wurden
	;VR: BX:=DI, AX
	call	ClearBufForDel
@@l:	cmp	[Buf2+bx],40h	;Unterseite mind. 1x eingelesen?
	jnc	@@2		;NICHT löschen!
	push	cx
	 mov	cx,bx
	 call	DeleteP1	;Eine Seite! Ohne Löschen des Puffers jedesmal
	pop	cx
@@2:	xchg	ax,bx
	 add	al,1
	 daa			;Immer nur dezimal!
	xchg	bx,ax
	cmp	di,bx
	jnc	@@l
ifdef verbose
	push	dx
	 PRINTSTAT	'DelFromTo'	;27,'[7mDelFromTo',27,'[0m'
	pop	dx
endif
	ret
	endp

proc GetRequestedPage
	;PA: CY=0: Eine Seite aus den Requestern wurde für geeignet befunden
	mov	si,[Ringzaehler]
	mov	cx,8+4		;len req1 + len req0
@@l:	push	cx
	 mov	dx,[si]
	 btst	dx,bit 15
	 jz	@@1
	 bres	dx,not 7ffh
	 mov	cx,[si+2]
	 call	CheckOtherSearchings ;Wenn jemand DIESE Seite sucht, NICHT suchen!
	 jnc	@@r		;Diese Seite sucht noch niemand...
@@1:	 add	si,4		;size tReq
	 cmp	si,ofs ReqE
	 jc	@@2
	 mov	si,ofs Req1	;Ring-Adressierung
@@2:	pop	cx
	loop	@@l
	stc
@@3:	mov	[Ringzaehler],si
	ret
@@r:	pop	ax		;Stack korrekt stellen
	mov	bl,1		;Priorität à priori stellen
	jr	@@3		;CY=0
	endp

proc GetUniqPredPage
	;VR: AX,CX
	call	PagePredict_Get	;DX=nächste Seite
	jc	@@e		;Keine Seite zu finden
	jr	@@r1a
@@r4:
GetUniqNextPage:
@@r1a:	call	PagePredict_Next
	jc	@@e		;Keine Seite zu finden, oder DX=AlteSeite
;Andere Akquisitoren befragen, ob sie nicht dasselbe suchen...
@@r1:	mov	cx,8000h	;Unterseite egal?
	call	CheckOtherSearchings
	jc	@@r4
@@e:	ret
endp GetUniqPredPage

proc CheckOtherSearchings	;Alle Acqs befragen, ob sie diese Seite suchen
	;PE: DX/CX: Seite/Unterseite
	;PA: CY=1: Seite/Unterseite wird bereits gesucht
	push	bx di
	 xor	bh,bh
@@rl:	 call	CalcAcqPtr	;BH->DI
	 mov	al,[acq.Zust]	;Nur "wartende" und "suchende" testen!
	 cmp	al,suchend
	 jz	@@r5
	 cmp	al,wartend
	 jnz	@@r3
@@r5:	 cmp	[acq.Page],dx
	 jnz	@@r3
	 cmp	[acq.Subp],cx	;Gleiche Unterseite?
	 stc
	 jz	@@e		;ja - raus!
	 btst	[acq.Subp],bit 15
	 stc			;Bei einem von beiden NoCare-Bits gestzt?
	 jnz	@@e		;jeweils raus!
	 btst	cx,bit 15
	 stc
	 jnz	@@e
@@r3:	 inc	bh
	 and	bh,3
	 jnz	@@rl
@@e:	pop	di bx
	ret
	endp


;################################################################
proc UpdateAllTimer
	;Nächste Aufgabe: Timerzellen aktualisieren
	;Nebenbei: Ton abschalten
	xor	dx,dx
	xchg	dx,[MyTimer]	;Dabei gleich nullsetzen
;	call	GetTimer	;Ticks aus 40:6C holen
;	mov	dx,ax
;	xchg	[OldTimer],ax
;	sub	dx,ax		;Differenz
	xor	bh,bh
@@1:	call	CalcAcqPtr
	 add	[acq.Zeit],dx
	inc	bh
	and	bh,3
	jnz	@@1
	;weitere Zellen...
	xor	ax,ax
	cmp	[stime],ax
	jz	@@2
	sub	[stime],dx
	ja	@@2
	mov	[stime],ax	;wieder nullsetzen
	call	NoSound
@@2:	btst	[ctrl0],bit 11
	jnz	@@3a		;Keine Aktion!
	cmp	[CurVT],0
	jz	@@3a		;Keine Aktion!
	sub	[pTime],dx
	ja	@@3
	mov	ax,300
	call	Pieps		;quittieren
	mov	al,80h
	call	Broadcast
ifdef Verbose
	push	dx
	 PRINTSTAT	'FERTIG'	;27,'[5mFERTIG',27,'[0m'
	pop	dx
endif
@@3a:	mov	[pTime],FERTIGTIMEOUT
@@3:	ret
	endp

;proc TimerInit
;	call	GetTimer
;	mov	[OldTimer],ax
;	ret
;	endp

;extrn __0040H:far

;proc GetTimer
;	pusha
;	 call	GetTickCount
;	popa
;	push	ds
;	 push	ofs __0040H
;	 pop	ds
;	 mov	ax,[ds:6Ch]
;	pop	ds
;	ret
;endp

;################################################################
proc InitAcq
	;Starte Suchvorgang
	;und trägt "aktive Suche" ein
	;PE: DX: Page, Bit15: Don't Care
	;    CX: Subp, Bit15: Don't Care
	;    BH: Acq-Nummer (0..3), BL: Privilege Level
	;PA: CY: Fehler
	;VR: AX,SI
	call	ProgAcq		;Nur programmieren mit DX-CX
	jc	@@e
	mov	[acq.Page],dx	;Page, Seite
	mov	[acq.Subp],cx	;Subp, Unterseite
;	mov	[acq.Level],bl	;Privileg
ifdef Verbose
	push	di
	 mov	di,ofs Buf
	 mov	al,'<'		;Zeichen: Starte Suche
	 stosb
	 mov	ax,dx
	 call	PutPageOrStar
	 mov	al,'/'
	 stosb
	 mov	ax,cx
	 call	PutSubPageOrStar
	 mov	al,'L'
	 stosb
	 mov	al,bl		;Level-Angabe
	 call	putHexNibble
	 mov	al,0
	 stosb
	pop	di
	push	bx		;Acq
	push	ds ofs Buf	;Msg
	push	1		;New=true
	call	Message
endif
@@e:	ret
	endp

proc putSubPageOrStar
	BTST	ax,bit 15
	jz	putHexAX
@@star:	mov	al,'*'
	stosb
	ret
putPageOrStar:
	BTST	ax,bit 15
	jnz	@@star
	xchg	al,ah
	or	al,al
	jnz	@@1
	add	al,8		;0xx->8xx
@@1:	call	putHexNibble
	xchg	al,ah
	jmp	putHexAL
endp

proc putHexAX
	xchg	al,ah
	call	putHexAL
	xchg	al,ah
putHexAL:
	push	ax		;Werte erhalten
	 shr	al,4
	 call	putHexNibble
	pop	ax
putHexNibble:
	and	al,0fh
	add	al,90h		;Hex -> ASCII
	daa
	adc	al,40h
	daa
	stosb
	ret
endp

;################################################################

proc DelDisp	;soll später mal ALLE PASSENDEN Seiten DX/CX löschen
	;PE: DI: Zeiger auf Akquisitor-Spiegel
	mov	dx,[acq.Page]
	mov	cx,[acq.SubP]
	mov	bl,[acq.Level]
	cmp	bl,3
	jnc	@@1
	call	AckNotFounds
	call	Pagepredict_Delete ;bei Level<3 Seite aus Prädiktor löschen
@@1:
ifdef Verbose
DATASEG
@@s	db	' ?',0
CODESEG
	push	bx
	push	ds ofs @@s
	push	0
	call	Message
endif
	cmp	bl,3
	jnc	@@2
	call	DeletePage	;Bei Level<3 Seite aus Index löschen
ifdef Verbose
DATASEG
@@del	db	'L÷schen der Seite',0
CODESEG
	push	bx
	push	ds ofs @@s
	push	1
	call	Message
endif
@@2:	ret
	endp

	push	bx di
	jr	dp1

proc DeletePage
	;Löscht die Seite(n) DX/CX aus Index und Datei
	call	ClearBufForDel
DeleteP1:
	push	bx di
dp1:	 push	dx
	  call	SeekInIdx	;DX/CX->DX
	  jc	@@e
	  inc	[Loecher]
	  inc	[Stats.Deletes]
	  call	FromDeletePage	;als "neue Seite" speichern
	 pop	dx
	 jr	dp1
@@e:
ifdef Verbose
	PRINTSTAT 'X'
endif
	  cmp	[Loecher],MAXLOECHER ;10 Löcher erreicht?
	  jc	@@1
	  call	VTFile_Garb_Init ;Garbage Collection aktivieren
@@1:	 pop	dx
	pop	di bx
	ret
	endp

proc ClearBufForDel c
 uses cx,di
	mov	di,ofs Buf
	mov	cx,512		;len Buf/2
	xor	ax,ax
	rep	stosw		;Seite gründlich löschen (Testzwecke)
	bset	<[wo Buf]>,bit 15 ;Seiten-Loch!
	ret
	endp

;################################################################
proc UpdDisp c
 uses bx,di
	call	AckRequests
	cmp	[CurVT],0	;Videotext-Sendername
	jz	@@e		;es MUSS ein Sendername vorhanden sein
;Eigentlich dürfte es HIER NIE klingeln, weil das von LiesSeite
;abgecheckt werden müßte. Aber ich entscheide mich hier für "doppelt
;hält besser"!
	call	UpdateNewPage
@@e:	ret
	endp

proc AckRequests
	;Requests beantworten, weil Seite gefunden
	;Voraussetzung: Seite "modifiziert"
	mov	dx,[wo Buf]
	mov	cx,[wo Buf+2]
	mov	bl,8+4		;len req1 + len req0
	mov	si,ofs req1
@@l:	mov	ax,[si]
	btst	ax,bit 15
	jz	@@1
	and	ax,7ffh
	cmp	ax,dx		;Seite gleich?
	jnz	@@1
	mov	ax,[si+2]	;Unterseite
	btst	ax,bit 15	;egal?
	jnz	@@2		;ja
	cmp	ax,cx		;gleich
	jnz	@@1		;nein...
@@2:	mov	al,[si+1]
	bres	<[wo si]>,bit 14
	test	al,bit 6
	jnz	@@3
	bres	<[wo si]>,bit 15
	jr	@@4
@@3:	mov	[si+2],cx	;Gefundene Unterseite
@@4:	cmp	si,ofs req0
	jc	@@6
	mov	al,84h
	call	Broadcast
	jr	@@1
@@6:	bset	[ctrl0],bit 8	;Semaphordatei schreiben
@@1:	add	si,4
	dec	bl
	jnz	@@l
	ret
	endp

proc AckNotFounds c
 uses bx
	;Requests mit NOT FOUND beantworten, weil Seite nicht gefunden
	mov	bx,8+4		;len req1 + len req0
	mov	si,ofs req1
@@l:	mov	ax,[si]
	btst	ax,bit 15
	jz	@@1
	and	ax,7ffh
	cmp	ax,dx		;Seite gleich?
	jnz	@@1
	btst	cx,bit 15	;NoCare für Unterseite?
	jnz	@@2
	cmp	[si+2],cx	;Unterseite gleich?
	jnz	@@1		;nein... (gerade mal so gerettettet)
@@2:	bset	ax,bit 13	;Not Found-Quittung
	mov	[si],ax
	bset	[ctrl0],bit 8	;Semaphordatei schreiben
@@1:	add	si,4
	dec	bx
	jnz	@@l
	ret
	endp

;************************************************************************
;*									*
;*	Hier muß dringend eine XMS-gestützte Fehlererkennung hin!	*
;*									*
;************************************************************************

proc SeekInIdx c
 uses bx,si,di

	;Sucht Seite DX/CX in Liste
	;PE: DX-CX Seite-Unterseite
	;PA: DX:Index
	;VR: AX,DX
	;CY=1: nicht gefunden
	;CY=0: gefunden, dann DX=Index
	;
	mov	ax,dx
	mov	si,cx
	mov	cx,[CurIdx]	;Anzahl der Indizes
	mov	di,ofs Index
	xor	dx,dx
	jcxz	@@1
@@2:	scasw
	jz	@@3
@@4:	inc	di
	inc	di
	inc	dx		;Indexzähler
	loop	@@2
@@1:	stc
@@5:	xchg	cx,si		;CX zurückstellen
	ret
@@3:
	btst	si,bit 15	;NoCare für Unterseite?
	jnz	@@5		;ja, gleich zum Ende kommen!
	mov	bx,si
	xor	bx,[di]
	and	bx,3f7fh	;Unterseite ohne Bits 14 und 15!
	jnz	@@4
	jr	@@5
endp

proc UpdateNewPage
	;Voraussetzung: VT-Datei muß offen sein!
	;In BUF liegt eine Videotextseite mit eingetragenen Header-
	;und Trailerdaten vor!
	;HINWEIS: Update erfolgt nur, wenn es sich um KEINE Untertitel
	;handelt. Einzige Ausnahme sind Untertitelrequests vom Level 2
	;(via Semaphorendatei)

	;PE: Buf: Videotextseite mit Seite/Unterseite
	;Routine sucht im Index nach bereits passender Seite
	;Wenn gefunden, dann Vergleichen und Überschreiben
	;Wenn nicht gefunden, dann Anhängen

	mov	[gpi_scratch],bx
	push	bx
	push	ds ofs @@nix
	push	1
	call	Message

	mov	si,ofs Buf
	mov	dx,[si]		;Seite laden
	mov	cx,[si+2]	;Unterseite
	call	SeekInIdx	;Suchen
	jnc	@@4
;Nicht gefunden, also anhängen! (KEINE Löcher ausfüllen)
	btst	[ctrl0],bit 10	;Schutz vor unvollständiger Tabelle
	jnz	@@e		;Neue Seite verwerfen
	mov	dx,[CurIdx]
	cmp	dx,[MaxIdx]
	jnc	@@5		;Fehler:Tabelle voll
ifdef Verbose
DATASEG
@@new	db	'Neue Seite'
@@nix	db	0
CODESEG
	push	bx
	push	ds ofs @@new
	push	0
	call	Message
endif
	call	AddNewPage	;Datei verlängern
	jc	@@e
	inc	[CurIdx]	;Beim fehlerfreien Schreiben
	mov	bx,[CurVTHandle]
	DOS	45h		;DUP
	jc	@@e		;bei "no more handles"
	xchg	bx,ax
	DOS	3eh		;Bei jeder NEUEN Seite flushen!
@@e:	ret
@@5:	; Indextabelle leidet an Überläufen
	cmp	[Loecher],0	;Sind Löcher da?
	jz	@@6		;nein: Pumpe!
	call	VTFile_Garb_Init ;Eine "Garbage" auslösen (trotzdem Seite verwerfen)
@@6:	bset	[ctrl0],bit 12	;Seite verwerfen (Träne)
	ret
@@4:	;Schon mal gefunden
;	call	UpdatePage
;	ret
	endp

proc UpdatePage	;wird von UPDATE gerufen bei Wiederauffindung einer Seite
	;PE: DX: Index
	;   Buf: Die Videotextseite
	call	VTFileRead	;nach BUF2
	mov	si,ofs Buf+40
	mov	di,ofs Buf2+40
	mov	cx,23*40/2	;23 Zeilen vergleichen
	repe	cmpsw		;(also außer Kopfzeile und Statusmeldungen)
	pushf
	 call	CalcDXPtr	;DX->DI
	popf
	jnz	@@1		;wenn ungleich
	inc	[Stats.Equals]
ifdef Verbose
	push	dx
	 btst	[req.SubP],bit 15
	 leaz	dx,'Dreifach gefunden'	;Dreifach gefunden
	 jnz	@@t1
	 leaz	dx,'Doppelt gefunden'	;Doppelt gefunden
@@t1:
	 push	[gpi_scratch]
	 push	ds dx
	 push	0
	 call	Message
	pop	dx
endif
	bset	[req.SubP],bit 15 ;Doppelt-gefunden-Flag:=1
	jr	@@3		;Dennoch schreiben (Uhrzeit!)
@@1:	;wenn Vergleich fehlerhaft...
ifdef Verbose
	push	dx
	 btst	[req.SubP],bit 15
	 LEAZ	dx,'Fehler nach 2*OK'	 ;Nach "Doppelt gelesen" fehlerhaft
	 jnz	@@u1
	 btst	[req.SubP],bit 14
	 LEAZ	dx,'Zweites Update' ;Zweites Update
	 jnz	@@u1
	 LEAZ	dx,'Erstes Update' ;Erstes Update
@@u1:
	 push	[gpi_scratch]
	 push	ds dx
	 push	0
	 call	Message
	pop	dx
endif
	btst	[req.SubP],bit 15 ;Vorher 2x okay gewesen?
	jz	@@nf		;Kein "Fault"
	inc	[Stats.Faults]
	bres	[req.SubP],bit 15 ;Sowieso rücksetzen
	jr	@@e
@@nf:
	inc	[Stats.Updates]
	jr	@@3
AddNewPage:	;wird von UPDATE gerufen bei Dateiverlängerung
	;PE: DX: Index
	;   Buf: die Videotextseite
	;Kein Vergleich!
	inc	[Stats.News]
FromDeletePage:
	call	CalcDXPtr	;DX->DI
	mov	si,ofs Buf
	push	di
	 movsw			;Neuen Indexeintrag kreieren
	 movsw			;Index OK, Doppelt-gefunden-Flag:=0
	pop	di
;dann wird eine Kennung ausgegeben (fälliger Senderwechsel)
@@3:	bset	[req.SubP],bit 14 ;Setzen eines Geschrieben-Bits
	mov	si,ofs Buf
	call    VTFileWriteFrom	;ab SI saven
@@e:	ret
	endp

proc StdDosErrH
	bset	[ctrl0],bit 14	;Fehler mit *.VT-Datei
	mov	[DosError],al	;Letzten DOS-Fehler merken
	stc
	ret
	endp

;################################################################
proc VTFilePos
	;PE: DX=Position in Kilobytes
	;PA: BX:Handle, >=5 getestet
	;VR: AX,BX,DX
	mov	bx,[CurVTHandle]
	cmp	bx,5		;Handle okay? (Sicherheitshalber)
	jnc	FilePos
	mov	al,6		;Ungültiges Handle
	jmp	[DosErrH]	;wenn Handle nicht okay
FilePos: ;Positioniere Dateizeiger Handle BX nach DX*1024
	push	cx
	 mov	ax,1024		;len Buf2
	 mul	dx		;DX=High-Word
	 mov	cx,ax		;CX=Low-Word
	 xchg	dx,cx		;Umdrehen
	 DOS	4200h
	 jnc	@@e
todose:	 call	[DosErrH]	;Handler rufen
@@e:	pop	cx
	ret
	endp

proc VTFileRead			;Ziel fest auf Buf2
	;1 Record vom VT-File lesen, DX=Index
	;VR: AX
ifdef Verbose
	PRINTSTAT	'R'
endif
	;liest den Record DX nach Buf2,
	;CY=1: DOS-Fehler
	;CY=0 & Z=1: Record komplett gelesen
	push	cx bx dx
	  call	VTFilePos	;Dateizeiger bewegen
	  mov	dx,ofs Buf2
	  mov	cx,1024		;len Buf2	;1 Kilobyte
	  DOS	3fh		;lesen
	 pop	dx bx
	 jc	todose		;Fehler markieren
	 cmp	cx,ax		;CX>=AX!
	pop	cx
	ret
	endp

proc VTFileWrite		;Quelle fest
	;1 Record zum VT-File schreiben, DX=Index
	;VR: AX,SI
	mov	si,ofs Buf2
VTFileWriteFrom:		;Quelle bestimmbar!
	;schreibt den Record DX aus [SI],
	;CY=1: Sonstiger Fehler, auch: Platte voll
ifdef Verbose
	PRINTSTAT	'W'
endif
	push	cx bx dx
	  call	VTFilePos	;Dateizeiger bewegen
	  mov	dx,si
	  mov	cx,1024		;len Buf2	;1 Kilobyte
	  DOS	40h		;schreiben
	 pop	dx bx
	 jc	todose		;Fehler markieren
	 cmp	ax,cx
	 jnc	@@1
	 bset	[ctrl0],bit 15	;DISK FULL
@@1:	pop	cx
	ret
	endp

;################################################################
vtgr1:	inc	[GarbDIdx]
proc VTFile_Garb_Run
	;bewegt genau einen Record oder gar keinen, wenn Ende erreicht
@@3:	mov	dx,[GarbDIdx]	;Suchindex
	cmp	dx,[CurIdx]	;Ende erreicht?
	jnc	VTFile_Garb_Done;Ja - fertig!
	call	CalcDXPtr	;DX->DI
	btst	<[wo di]>,bit 15 ;markiert gelöschten Eintrag
	jz	vtgr1		;Schon fertig mit dieser Runde, nächste Runde
	mov	dx,[CurIdx]
	dec	dx
	call	CalcDXPtr
	btst	<[wo di]>,bit 15 ;Dort auch gelöscht?
	jz	@@w		;ja, nicht schaufeln
	call	@@d
	jr	@@3
@@w:
	xchg	si,di		;als Quellindex retten
	call	VTFileRead	;liest ab DX nach Buf2
	jc	@@e		;DOS-Fehler
	jnz	@@e		;Nicht komplett gelesen - Fehler
	mov	dx,[GarbDIdx]
	call	VTFileWrite
	jc	@@e		;DOS-Fehler UND Disk full
	call	CalcDXPtr
	movsw
	movsw			;Index kopieren (mit allen Zusatzinfos)
	inc	[GarbDIdx]	;Neuer Betrachtungspunkt
@@d:	dec	[Loecher]
	dec	[CurIdx]	;Neues Dateiende
@@e:
dg2:	ret
	endp

proc VTFile_Garb_Done
	mov	bx,[CurVTHandle]
	DOS	45h		;Handle verdoppeln
	jc	dg2		;Nichts tun bei Fehler, nächste Gelegenheit
				;abwarten (?) (No more handles)
	xchg	bx,ax
	mov	dx,[CurIdx]
	call	FilePos		;bezüglich Handle-Duplikat diesmal!
	xor	cx,cx
	DOS	40h		;Abschneiden
	DOS	3eh
EndGarbage:
	bres	[ctrl0],bit 9	;GARBAGE abschalten
	jr	incGF
	endp

proc VTFile_Garb_Init
	;die entsprechende Initialisierungsprozedur
	btst	[ctrl0],bit 9	;Schon eingeschaltet?
	jnz	@@e		;Nicht schon wieder!
ifdef Verbose
	PRINTSTAT	'G'
endif
	mov	[GarbDIdx],0	;Destination Index
	bset	[ctrl0],bit 9	;Garbage Mode einschalten
incGF:	bset	[ctrl0],bit 8	;Semaphorendatei erneuern (lassen)
	inc	[GarbFlg]	;Zähler für Garbage
@@e:	ret
	endp

;################################################################
proc VTFile_Load_Run
	;(Wenn entsprechendes Flag (Bit2[ctrl1]) aktiv)
	;genau einen Record einlesen und Index erweitern,
	;ggf. Anforderung löschen
	mov	dx,[CurIdx]
	call	VTFileRead
	jc	@@e
	jnz	VTFile_Load_Done	;Datei zu Ende
	cmp	dx,[MaxIdx]
	jnc	@@1		;Flag löschen: Datei zu lang
	inc	[CurIdx]
	call	CalcDXPtr	;dx->di
	mov	si,ofs Buf2
	btst	[ctrl0],bit 1	;Pseudoseiten eingeschaltet?
	jnz	@@2
	mov	ax,[wo si]
	call	CheckPseudoPage
	jc	@@4
	mov	ax,[wo si+2]
	call	CheckPseudoSubPage
	jc	@@4
@@2:	BTST	<[wo si]>,bit 15 ;Loch?
	jz	@@3
@@4:	bset	<[wo si]>,bit 15 ;Mach ein Loch, wenns noch keins ist!
	inc	[Loecher]	;die Löcher auf dem laufenden halten
@@3:	mov	dx,[si]
	movsw
	movsw			;Index vervollständigen
	call	PagePredict_Put	;Seite eintragen
@@e:	ret
@@1:	bset	[ctrl0],bit 12	;Datei zu lang bzw. Index zu kurz
	endp

proc VTFile_Load_Done
	bres	[ctrl0],bit 10	;DoLoadFile.Done
	cmp	[Loecher],MAXLOECHER
	jc	@@1
	call	VTFile_Garb_Init ;evtl. GLEICH den Init ausführen
@@1:	jmp	SetWS
	endp

	_PATHCOPY		;Aus der dicken Bibliothek
proc ExpandVTIFile
	;PA: DI zeigt hinter die Null in Buf2
	;    DX zeigt nach Buf2
	mov	di,ofs Buf2	;Universalpuffer - Mädchen für alles
	push	di
	 mov	si,ofs SemaFile	;Pfad gleichsetzen
	 call	PathCopy
	 mov	si,ofs CurVT
	 dec	di		;AUF die Null
	 call	StrCpy
	 mov	si,ofs VTI$	;Abrakadabra..
	 dec	di		;AUF die Null
	 call	StrCpy		;Fertig ist der Dateiname
	pop	dx
	ret
	endp

proc VTFile_Load_Init
	;die entsprechende Initialisierungsprozedur
	;PE: [CurVT] Videotext-Sendername
	call	ExpandVTIFile
	DOS	41h		;Indexdatei löschen, evtl. Fehler ignorieren
	mov	[by di-2],0	;String kürzen... (nur noch *.VT)
	DOS	3d02h		;Zum Lesen und Schreiben öffnen
	jnc	@@1
	cmp	ax,2		;Nicht gefunden?
	stc
	jnz	@@e		;Alle anderen Fehler abschmettern
	xor	cx,cx		;Keine besonderen Attribute
	DOS	3ch		;Create
	jc	@@e
@@1:	mov	[CurVTHandle],ax;abspeichern
	xor	ax,ax
	mov	[CurIdx],ax	;An den Anfang
	mov	[Loecher],ax	;Auch Anzahl der Löcher rücksetzen
	mov	[DosError],al	;auch die Dosenfehler rücksetzen, NICHT das Bit
	bset	[ctrl0],bit 10 + bit 11 ;Einleseflag setzen
@@e:	jnc	@@nf
	call	[DosErrH]
@@nf:	ret
	endp

proc VTFile_Close
	bres	[ctrl0],bit 12	;Datei-Überlänge-Flag löschen
	btst	[ctrl0],bit 9	;Garbage Collection aktiv?
	jz	@@1
	call	EndGarbage
@@1:	mov	bx,[CurVTHandle]
	DOS	3eh		;Schließen
	xor	ax,ax
	mov	[CurVTHandle],ax
	btst	[ctrl0],bit 6 + bit 10 ;Eins der Bits gesetzt?
	jnz	@@2
	cmp	[CurIdx],MINIDXFORVTI ;16
	jc	@@2
	call	WriteIndex
@@2:	mov	[CurVT],0	;Dateiname=''
SetWS:	bres	[ctrl0],bit 10	;DoLoadFile.Done
	bset	[ctrl0],bit 8	;Semaphorendatei neu schreiben
	ret
	endp

proc WriteIndex
	;Indextabelle präparieren...
	mov	cx,[CurIdx]
	mov	si,ofs Index+3
	jcxz	@@2
@@l:	bres	<[by si]>,bit 7 + bit 6 ;Unterseitenbits löschen
	add	si,4
	loop	@@l
@@2:	;Datei erzeugen
	call	ExpandVTIFile
	xor	cx,cx		;Kein besonderes Attribut...
	DOS	3ch		;Create
	jc	@@3		;Fehler ignorieren
	xchg	bx,ax		;Handle
	;und schreiben
	mov	dx,ofs Index
	mov	cx,[CurIdx]
	shl	cx,1
	shl	cx,1		;*4 bitte!
	DOS	40h		;schreiben
	DOS	3eh		;und zumachen
@@3:	ret
	endp

;################################################################
;GetBroadCaster:

	_STRCOMP

proc CheckHL c
 uses di,si,dx,cx,bx
	;PA: CY=1: Name ungleich, Seite sollte verworfen werden
	;Sollte der falsche Name 2mal hintereinander falsch sein,
	;löst CheckHL einen Wechsel der .VT-Datei aus!
	call	PGTime_Check	;Bei (sicher seltenen) Uhrzeitfehlern
	mov	si,ofs Buf+8
	push	si di
	 mov	di,ofs HLineCopy
	 mov	cx,32/2
	 rep	movsw
	 inc	[HLineChange]	;Veränderungszähler
	pop	di si
	call	ExtractName	;fest nach Buf2 (!)
	mov	si,ofs Buf2	;Ausgelesener String
	cmp	[by si],0	;leer? (wegen Fehler z.B.)
	jz	@@3
	mov	di,ofs CurVT	;Offene .VT-Datei
	call	StrComp
	jz	@@e1		;HL völlig okay
	mov	di,ofs nbuf
	call	StrComp
	jnz	@@1		;Name tauchte erstmalig auf
	dec	[DisCount]	;Zählen des Auftretens der "seltsamen" Zeile
	stc
	jnz	@@e		;Noch nicht oft genug der neue Name
	cmp	[CurVTHandle],0
	jz	@@2
	call	VTFile_Close
@@2:	mov	ax,800		;Freudenpieps bei *jedem* NEUEN Sender
	call	Pieps
	mov	si,ofs nbuf
	mov	di,ofs CurVT
	call	strcpy
ifdef Verbose
	push	ds ofs CurVT
	push	1		;Neue Zeile!
	call	MessageStat
endif
	bset	[ctrl0],bit 8	;Semaphorendatei neu schreiben
	call	PagePredict_Init
	call	PGTime_Init	;die Korrektur defekter Uhrzeiten
	call	MSList_Init	;die Maximum-Subpage-Liste
	call	ResetSeeks	;Alle noch anstehenden Requests löschen
	call	VTFile_Load_Init ;Beginn mit dem Einlesen der .VT-Datei
	jnc	@@e
	mov	[CurVT],0	;CurVT="", Dateiname löschen...
	call	[DosErrH]
	jr	@@e
@@1:	;wenn Name<>nbuf und Name<>CurVT
	call	strcpy
@@3:	stc			;Seite verwerfen
@@e1:	mov	al,MAXDISCOUNT	;Zähler für Stringvergleich setzen
	pushf
	 btst	[ctrl0],bit 11	;Neuer Sendername fällig?
	 jz	@@e3		;dann eine hohe Zahl.
	 btst	[ctrl0],bit 0	;rolling header?
	 jnz	@@e2		;wenn nein bei der niedrigen Zahl bleiben.
@@e3:	 mov	al,MAXDISCOUNT*5
@@e2:	popf
	mov	[Discount],al
@@e:	ret
	endp

proc Pieps
	;PE: AX=Tonhöhe
	btst	[ctrl0],bit 5	;Quiet-Bit gesetzt?
	jnz	@@e
	call	Sound
	mov	[stime],PIEPSLEN ;Feste Länge 4 Ticks
@@e:	ret
	endp

	_SOUND


;##################################
;### Simple Berechnungsroutinen ###
;##################################
CalcDXPtr:	;aus DX (Datei-Index) -> DI berechnen
	mov	di,dx
	shl	di,1
	shl	di,1
	add	di,ofs Index
	ret

CalcAcqPtr:	;aus BH die zugehörige Speicheradresse nach DI berechnen
	push	ax
	 mov	al,SIZE tAcq
	 mul	bh
	 mov	di,ax		;Werte eintragen
	 add	di,ofs Acq0
	pop	ax
	ret
Detected encoding: OEM (CP437)1
Wrong umlauts? - Assume file is ANSI (CP1252) encoded