UNIT jobs; {$project vt } { Job-Verwaltung zum Programm VideoText } INTERFACE; FROM vt USES datei; VAR editor: str80; toplevel: Integer; active: Byte; { aktive Jobs in der Seitensuche } maxwait, burst,shuffle: Integer; PROCEDURE uhrzeit(VAR zeit: zeiteintrag); FUNCTION diff_time(alt, neu: zeiteintrag): Long; PROCEDURE sleep; PROCEDURE wakeup; PROCEDURE kill_queue; PROCEDURE handle_queue; PROCEDURE handle_jobs; PROCEDURE attempt_input(job: Integer); PROCEDURE pgstr2numbers(s: str80; VAR pg, sp: Integer); PROCEDURE add_job(entry: str80; blind: Boolean); PROCEDURE kill_job(nr: Integer); PROCEDURE cancel_job(page: Integer); PROCEDURE hurricane; FUNCTION do_retry: Integer; PROCEDURE page_grabber(mode: Byte); PROCEDURE topgrab(pg0: p_onepage); PROCEDURE getconfig(nr: Integer); FUNCTION ed_config(hint: p_onepage): Boolean; FUNCTION ed_stations: Boolean; PROCEDURE dump_numbers; PROCEDURE dump_title(seite: p_onepage); { ---------------------------------------------------------------------- } IMPLEMENTATION; {$ opt q,s+,i+} { keine Laufzeitprüfungen außer Stack und Feldindizes } VAR bedtime: zeiteintrag; wanted: ARRAY [$100..$8FF] OF Boolean; STATIC; PROCEDURE uhrzeit{(VAR zeit: zeiteintrag)}; BEGIN telltime(zeit.tage,zeit.min,zeit.tics); END; PROCEDURE add_time(delta: zeiteintrag; VAR zeit: zeiteintrag); BEGIN IF zeit.tics + delta.tics>=3000 THEN Inc(zeit.min); zeit.tics := (zeit.tics + delta.tics) MOD 3000; IF zeit.min + delta.min>=1440 THEN Inc(zeit.tage); zeit.min := (zeit.min + delta.min) MOD 1440; zeit.tage := zeit.tage + delta.tage; END; PROCEDURE sub_time(delta: zeiteintrag; VAR zeit: zeiteintrag); BEGIN IF zeit.tics - delta.tics<0 THEN Dec(zeit.min); zeit.tics := (zeit.tics - delta.tics + 3000) MOD 3000; IF zeit.min - delta.min<0 THEN Dec(zeit.tage); zeit.min := (zeit.min - delta.min + 1440) MOD 1440; zeit.tage := zeit.tage - delta.tage; END; FUNCTION diff_time{(alt, neu: zeiteintrag): Long}; { liefert die Differenz zwischen zwei Zeitpunkten in Ticks (1/50-Sekunden) } BEGIN diff_time := neu.tics - alt.tics + 3000 * ( (neu.min - alt.min) + 1440 * (neu.tage - alt.tage) ); END; PROCEDURE sleep; { wird vor Unterbrechung der Hauptschleife (z. B. durch FileRequester) } { aufgerufen } BEGIN uhrzeit(bedtime); END; PROCEDURE wakeup; { Verhindert in Zusammenarbeit mit sleep, daß Zeiten, während derer der } { VT-Decoder gar nicht abgefragt wird, zum Löschen von Jobs wegen } { Zeitüberschreitung führen. } VAR delta: zeiteintrag; j: Integer; BEGIN uhrzeit(delta); sub_time(bedtime,delta); FOR j := 0 TO maxactive-1 DO add_time(delta,activejobs[j].lastaction); END; PROCEDURE kill_queue; VAR i: Integer; BEGIN queued := 0; IF thisjob<0 THEN thisjob := 0; FOR i := 0 TO maxactive-1 DO BEGIN activejobs[i].pg := 0; sperren(i); END; END; PROCEDURE count_them; { durchzählen, wer in der Seitensuche alles bedient werden will: } VAR j: Integer; BEGIN active := 0; FOR j := 0 TO maxactive-1 DO IF (activejobs[j].pg>0) THEN Inc(active); END; PROCEDURE handle_queue; { Verwaltet das Aufrücken wartender Jobs. } { Jobs mit unbestimmter Unterseitennummer, also mit /0, /*, /., /! können } { aktive Jobs mit gleicher Seitennummer aus der Seitensuche verdrängen } VAR i,j,killer,moved: Integer; BEGIN moved := 0; REPEAT j := -1; IF queued>0 THEN BEGIN { Soll ein aktiver Job verdrängt werden? } IF queue[firstinq].sp<1 THEN FOR i := 0 TO maxactive-1 DO IF activejobs[i].pg=queue[firstinq].pg THEN j := i; { Oder ist ein Platz in der Seitensuche frei? } IF j<0 THEN FOR i := maxactive-1 DOWNTO 0 DO IF activejobs[i].pg=0 THEN j := i; END; IF j>=0 THEN BEGIN { Empfangseinheit mit wartendem Job belegen } { Ein wartender Job besteht nur aus Seiten- und Unterseitennummer, } { jetzt kommen eine Menge Informationen dazu. } WITH activejobs[j] DO BEGIN pg := queue[firstinq].pg; sp := queue[firstinq].sp; sp_count := 0; sp_max := 0; holen := False; erledigt := False; FOR i := 0 TO maxsubpage DO sp_check[i] := False; uhrzeit(lastaction); anfordern(j,pg,0,%111); END; IF i2c_status<>0 THEN BEGIN { Oh Mann! Dummer I²C-Bus! } activejobs[j].pg := 0; { Kommando zurück } j := -1; { hier ist nichts mehr zu holen } END ELSE BEGIN { Warteschlange aufrücken: } Dec(queued); Inc(firstinq); IF firstinq>qlen THEN firstinq := 1; { Auswahlzeiger des Benutzers dem Aufrücken entsprechend nachführen: } IF thisjob=-1 THEN thisjob := j ELSE IF thisjob<0 THEN Inc(thisjob); IF thisjob>=0 THEN display_select(thisjob); Inc(moved); END; END; UNTIL j=-1; IF moved>0 THEN redraw_queue(-1); count_them; END; PROCEDURE requeue(i: Integer; fifo: Boolean); { einen aktiven Job in die Warteschlange zurückstellen } VAR j: Integer; BEGIN IF (queued0) THEN BEGIN IF fifo THEN BEGIN j := firstinq+queued; IF j>qlen THEN j := 1; END ELSE BEGIN Dec(firstinq); IF firstinq=0 THEN firstinq := qlen; j := firstinq; END; Inc(queued); queue[j].pg := activejobs[i].pg; queue[j].sp := activejobs[i].sp; END; activejobs[i].pg := 0; sperren(i); END; PROCEDURE rearrange; { ersten und zweiten Platz der Warteschlange vertauschen } VAR i, j, hilf: Integer; BEGIN IF queued>1 THEN BEGIN i := firstinq; j := i+1; IF j>qlen THEN j := 1; hilf := queue[i].pg; queue[i].pg := queue[j].pg; queue[j].pg := hilf; hilf := queue[i].sp; queue[i].sp := queue[j].sp; queue[j].sp := hilf; END; END; PROCEDURE rausschmeisser; { Prüfen, ob ein Job wegen Zeitüberschreitung gestrichen werden kann. } { Passend zum gelöschten Job wird anschließend eine Dummy-Seite mit } { teilnahmsvoller Meldung in die Liste eingereiht. } VAR i, j: Integer; jetzt: zeiteintrag; seite: p_onepage; BEGIN uhrzeit(jetzt); FOR j := 0 TO maxactive-1 DO WITH activejobs[j] DO IF (pg<>0) AND (diff_time(lastaction,jetzt) > 50*maxwait) AND (sp>-2) THEN BEGIN { aber keine "festgehaltenen" Seiten! } i := sp; IF i<0 THEN i := 0; seite := hunt_in_list(pg,i,True); IF seite=Nil THEN BEGIN New(seite); seite^.pg := pg; seite^.sp := i; init_page(seite); ins_to_list(seite); update_list(seite,1); END ELSE BEGIN seite^.pg := pg; seite^.sp := i; init_page(seite); END; write_to_page(0,2,' Seite '+hexstr(pg,3) +' nicht gefunden - Sorry',3,1,seite); write_to_page(0,3,' Suche nach '+IntStr(diff_time(lastaction, jetzt) DIV 50)+' Sek. abgebrochen',4,6,seite); write_to_page(0,5,' Nochmal anfordern: f8',3,1,seite); write_to_page(0,6,' oder diese Seite wegwerfen: Del',4,6,seite); IF thispage=seite THEN writepage(seite,True); pg := 0; sperren(j); redraw_queue(j); END; count_them; END; PROCEDURE handle_jobs; { Überprüft, ob in einem der Empfangskreise eine Seite eingetroffen ist, und } { wenn ja, ob sie aufgrund ihrer Unterseitennummer überhaupt eingelesen } { werden muß. Es wird auch entschieden, ob der Job durch die eingetroffene } { Seite erledigt ist. Kriterium für 'erledigt': } { Ein Job mit sp>0 ist erledigt, sobald die eine angeforderte Unterseite } { da ist. Ein Job mit sp=0 ist erst dann erledigt, wenn alle seine } { Unterseiten eingelesen wurden. Wann das ist, läßt sich nur raten, aber } { ganz gut raten. Und es gibt noch einige Sonderfälle mit sp<0 ... } VAR j: Integer; dummy: p_onepage; sp_decval: Integer; BEGIN rausschmeisser; { Schauen, ob irgendwo das Eintreffen einer Kopfzeile gemeldet wurde: } FOR j := 0 TO maxactive-1 DO WITH activejobs[j] DO IF (pg>0) AND NOT holen THEN IF seite_da(j) THEN BEGIN New(dummy); uhrzeit(lastaction); getpage(j,dummy,False); { *nur* Status und Seitennummer holen } akt_sp := dummy^.sp; sp_decval := get_bcd(akt_sp); { *** Schauen, ob die Seite eingelesen werden muß. Gründe, weswegen } { man eine Seite evtl. nicht haben will: } { 1.: Unterseite wurde bereits eingelesen. } { (Bei zu großen Unterseitennummern kann das nur über ein etwas } { armseliges Hilfskriterium festgestellt werden.) } IF (sp_decval<=maxsubpage) THEN holen := NOT sp_check[sp_decval] ELSE holen := (akt_sp>sp_max); { 2.: Nur eine Unterseite war angefordert, und zwar nicht diese. } IF sp>0 THEN holen := (akt_sp=sp); { Selbstnumerierende Unterseiten werden blind alle eingelesen, bis } { der Job erledigt ist: } IF sp<=-10 THEN BEGIN holen := True; akt_sp := make_bcd(sp_count+1); IF sp IN [-10,-11] THEN akt_sp := 0; sp_decval := get_bcd(akt_sp); END; IF holen THEN BEGIN { *** Unterseitenverwaltung aktualisieren: } Inc(sp_count); IF (sp_decval<=maxsubpage) THEN sp_check[sp_decval] := True; IF akt_sp>sp_max THEN sp_max := akt_sp; redraw_queue(j); { *** Schauen, ob magazinserielle oder -gemischte Übertragung } { vorliegt und danach die Wartezeit festlegen: } IF (dummy^.cbits AND PF_SERMAG)=0 THEN wartezeit := shuffle ELSE wartezeit := burst; END ELSE anfordern(j,pg,0,%111); { blöde Unterseite, Suche fortsetzen } { *** Prüfen, ob der Job durch die eingetroffene Seite erledigt ist. } { Das geht z. B. durch Unterseite 0 (= einzige Unterseite). } { auf keinen Fall aber durch eine Unterseite mit der bislang } { höchsten Nummer. } IF sp_check[0] THEN erledigt := sp_count>get_bcd(sp_max) ELSE IF akt_sp0) OR (sp=-1)) AND holen THEN erledigt := True; { Oder es sind genauso viele selbstnumerierende Unterseiten } { eingetroffen, wie angefordert waren. } IF (sp<-10) THEN erledigt := (sp_count=-sp-10); { überwachte Seiten sind aus kosmetischen Gründen immer "erledigt": } IF sp IN [-2,-3,-10] THEN erledigt := True; Dispose(dummy); { Evtl. noch eine Vergeltungsmaßnahme: einzelne Unterseiten- } { anforderung, zu der eine *falsche* Unterseite eingetroffen ist, } { muß eine andere vorbeilassen: } IF (sp>0) AND NOT holen AND (queued>0) THEN BEGIN requeue(j,False); rearrange; redraw_queue(-1); END; END; END; PROCEDURE attempt_input{(job: Integer)}; { Das Einlesen geschieht in einem zweiten Schritt, da nach Eintreffen der } { Kopfzeile erst eine Weile gewartet werden muß. } { Evtl. wird die Seite auch gleich ausgegeben: auf dem Bildschirm, falls } { auf den zugehörigen Job zeigt oder wenn eine festgehaltene } { Seite aktualisiert wurde; in die Ausgabedatei, falls es eine zu } { protokollierende Seite war. } { Jobs, die nach diesem Einlesen erledigt sind, wurden bereits entsprechend } { gekennzeichnet und werden aus der Liste gestrichen. } VAR dummy,seite: p_onepage; jetzt: zeiteintrag; exciting: Boolean; i: Integer; BEGIN { Prüfen, ob die Wartezeit für eine einzulesende Seite um ist: } WITH activejobs[job] DO IF (pg>0) AND holen THEN BEGIN uhrzeit(jetzt); IF diff_time(lastaction,jetzt) >= wartezeit THEN BEGIN { Seite einlesen: } { Ist bereits eine alte Version dieser Seite in der Liste, die dann } { lediglich überschrieben werden müßte? } seite := hunt_in_list(pg,akt_sp,True); IF seite=Nil THEN BEGIN New(seite); getpage(job,seite,True); IF sp<=-10 THEN seite^.sp := akt_sp; { selbstnumerierende Seite! } add_sp_number(seite); IF i2c_status<>0 THEN BEGIN Dispose(seite); Exit; END; ins_to_list(seite); update_list(seite,1); END ELSE BEGIN getpage(job,seite,True); IF sp<=-10 THEN seite^.sp := akt_sp; { selbstnumerierende Seite! } add_sp_number(seite); IF i2c_status<>0 THEN Exit; IF seite<>thispage THEN update_list(seite,0); END; { bildschirmüberwachte Seiten sind interessant, wenn sie das erste } { Mal eintreffen oder wenn sich der Inhalt geändert hat: } exciting := (sp=-2) AND ((sp_count=1) OR (seite^.cbits AND PF_RENEW<>0)) AND (seite^.cbits AND PF_STITLE=0) AND (seite^.sp=0); { Untertitel und Mehrfachseiten aber ausgenommen! } { bildschirmüberwachte Seite anzeigen: } IF (seite=thispage) OR exciting THEN BEGIN IF exciting THEN showscreen(2); IF seite<>thispage THEN BEGIN short_msg('neuer Inhalt S. '+hexstr(pg,3)+'!',0); writepage(seite,True); short_msg('bitte Leertaste drücken',0); END ELSE writepage(seite,True); END; { dateiüberwachte Seite abspeichern: } IF sp=-3 THEN IF (sp_count=1) OR (seite^.cbits AND PF_RENEW<>0) THEN BEGIN sleep; IF save_action(seite,1)<>0 THEN { nach fehlgeschlagenem Speichern sofort neuen Versuch: } sp_count := 0; wakeup; END ELSE short_msg('',0); holen := False; { beendet auch "Schonfrist" für erledigte Jobs } anfordern(job,pg,0,%111); { um PBLF wieder zu setzen } END; END; { Erledigten (und eingelesenen) Job löschen: } WITH activejobs[job] DO IF (pg>0) AND erledigt AND NOT holen THEN BEGIN IF (sp IN [-2,-3,-10]) THEN BEGIN { Sonderfälle: niemals erledigt } { nur die Zähler zurücksetzen, außer sp_count } sp_max := 0; erledigt := False; FOR i := 0 TO maxsubpage DO sp_check[i] := False; END ELSE BEGIN pg := 0; sperren(job); { löschen } END; redraw_queue(job); END; count_them; END; PROCEDURE pgstr2numbers{(s: str80; VAR pg, sp: Integer)}; VAR i,j,k: Integer; BEGIN i := Pos('/',s); j := Pos('*',s); IF j = 0 THEN j := Pos('-',s); { zwei Varianten ;-| } k := Length(s); IF i > 0 THEN BEGIN pg := hexval(Copy(s,1,i-1)); sp := hexval(Copy(s,i+1,k-i)); IF s[i+1]='*' THEN sp := -1; IF s[i+1]='.' THEN sp := -2; IF s[i+1]='!' THEN sp := -3; END ELSE IF j > 0 THEN BEGIN pg := hexval(Copy(s,1,j-1)); Val(Copy(s,j+1,k-j),sp,j); { "*"-Anzahl nicht als BCD! } sp := -10-sp; END ELSE BEGIN pg := hexval(s); sp := 0; END; END; PROCEDURE add_job{(entry: Str80; blind: Boolean)}; { Eine Eingabe, die eine Seitennummer darstellt (oder auch nicht), in die } { Warteschlange einzureihen versuchen. } { Bei blind=False wird noch überprüft, ob sich vielleicht bereits ein } { identischer Job in der Seitensuche befindet. } { Anschließend zeigt auf die neu besetzte Stelle. } VAR i,j,page,subpage: Integer; ok: Boolean; BEGIN pgstr2numbers(entry, page, subpage); ok := (page>=$100) AND (page<$900); { evtl. weitere Einschränkung: mit bereits vorhandenen Jobs vergleichen } { und keinen Job zulassen, der ein Verdrängen bewirken würde } IF NOT blind THEN BEGIN FOR j := 0 TO maxactive-1 DO IF (activejobs[j].pg=page) AND (subpage<1) THEN ok := False; FOR j := 1 TO queued DO BEGIN i := (firstinq + j - 2) MOD qlen + 1; IF (queue[i].pg=page) AND (subpage<1) THEN ok := False; END; END; IF ok AND (queuedqlen THEN j := 1; thisjob := -queued; END ELSE BEGIN Dec(firstinq); IF firstinq=0 THEN firstinq := qlen; j := firstinq; thisjob := -1; END; queue[j].pg := page; queue[j].sp := subpage; END; END; PROCEDURE kill_job{(nr: Integer)}; { einen Job löschen, nachführen, Bildschirm aber *nicht* } { aktualisieren } VAR j: Integer; BEGIN IF nr>=0 THEN BEGIN { aktiver Job } activejobs[nr].pg := 0; sperren(nr); END ELSE IF (-nr<=queued) THEN BEGIN { wartender Job } FOR j := -nr TO queued-1 DO queue[(firstinq+j-2) MOD qlen + 1] := queue[(firstinq+j-1) MOD qlen + 1]; Dec(queued); IF fifo AND (thisjob<=nr) THEN Inc(thisjob); { normal: thisjob=nr } IF -thisjob>queued THEN Inc(thisjob); END; END; PROCEDURE cancel_job{(page: Integer)}; { Als Erleichterung gegenüber kill_job() wird nicht die Position in der } { Warteschlange sondern der 'Name' des Jobs angegeben. } VAR j: Integer; BEGIN FOR j := 0 TO maxactive-1 DO IF activejobs[j].pg=page THEN kill_job(j); FOR j := -queued TO -1 DO IF queue[(-j+firstinq-2) MOD qlen + 1].pg=page THEN kill_job(j); END; PROCEDURE hurricane; { Die Seiten aus der Seitensuche zurück in die Warteschlange fegen. } VAR j: Integer; BEGIN FOR j := 0 TO maxactive-1 DO requeue(j,False); END; FUNCTION do_retry{: Integer}; { Nicht gefundene Seiten aus der Seitenliste entfernen und neu anfordern. } { Rückgabewert ist die Anzahl betroffener Seiten. } VAR refresh: Boolean; pg1, pg2: p_onepage; hits: Integer; s: String[20]; BEGIN hits := 0; refresh := False; pg1 := root; WHILE pg1<>Nil DO BEGIN pg2 := pg1^.next; IF (pg1^.cbits AND PF_LOCAL<>0) AND (pg1^.pg<$900) THEN BEGIN Inc(hits); IF pg1=visblpage THEN refresh := True; s := hexstr(pg1^.pg,3); s := s + '/'+hexstr(pg1^.sp,1) add_job(s, False); del_from_list(pg1); update_list(pg2,-1); END; pg1 := pg2; END; redraw_queue(-1); IF refresh THEN writepage(thispage, True); do_retry := hits; END; PROCEDURE page_grabber{(mode: Byte)}; { Rechenzeitintensive Variante der Seitensuche: alle Seiten einlesen, wie } { sie kommen. Mode=0: alle Seiten, mode=1: keine Pseudoseiten, mode=2: nur } { Seiten, die gerade in der Warteschlange stehen } { Prinzip des Algorithmus: } { Kreis 3 Kreis 2 Kreis 1 Kreis 0 (nach aufsteigender Priorität) } { * x x x | } { ===== * | === Kopfzeile * anfordern } { ----- | --- Folgezeile x sperren } { ----- | ^^^ Seite komplett } { ^^^^^ ===== * | } { ----- | Gesucht wird i. a. nach Seite } { ----- | "???", bei magazinparalleler } { ^^^^^ ===== * | Übertragung dagegen nach "X??", } { ----- | wobei X=1..8 für alle 4 Kreise } { ----- | gleich sein muß. } { ^^^^^ ===== | } { Jetzt sind die Seiten in 3, 2 und 1 stabil und komplett und können } { ausgelesen werden. } { Eine ganz naheliegende Idee wäre es, 3 und 2 bereits auszulesen, noch } { während man in 1 bzw. 0 auf Kopfzeilen wartet. } { Andererseits ist es wichtig, bereits die erste Seite, die nach der } { Anforderung eintrifft, im jeweiligen Kreis einzufrieren. Für alle } { danach eintreffenden Seiteninhalte wird der Speicher nämlich nicht mehr } { extra gelöscht, so daß unvollständig definierte Seiten (Schlagzeilen } { z. B.) mit ihren Vorgängern verschmelzen, was nicht so toll aussieht. } { Diese zeitoptimale Methode ist darum nur bei magazinparalleler } { Übertragung bedenkenlos möglich. Dort treffen aufeinanderfolgende } { Seiten eines Magazins nur ca. alle 0.8 sec ein, und so schnell geht das } { Einlesen über den I²C-Bus noch allemal (ca. 0.4 sec/Seite). } VAR i, j, mag, anz, neu, lastq: Integer; seite, dummy: p_onepage; timeout, parmode, redraw: Boolean; datei: Text; sender, zeile, name: str80; PROCEDURE waitforpg(unit: Integer); { max. 5 Sekunden auf das Eintreffen einer Seite warten } VAR t0,t: zeiteintrag; BEGIN uhrzeit(t0); REPEAT uhrzeit(t); timeout := diff_time(t0,t)>250; UNTIL seite_da(unit) OR timeout; END; PROCEDURE einlesen(unit: Integer); { neue Seite einlesen (sofern nicht schon vorhanden) und einreihen } VAR style: Integer; BEGIN style := 0; getpage(unit,dummy,False); Inc(anz); IF wanted[dummy^.pg] THEN BEGIN seite := hunt_in_list(dummy^.pg,dummy^.sp,True); IF seite=Nil THEN BEGIN New(seite); Inc(neu); style := 1; getpage(unit,seite,True); add_sp_number(seite); ins_to_list(seite); update_list(seite, 1); IF (mode=2) AND (dummy^.sp IN [0,1]) THEN cancel_job(dummy^.pg); END; END; IF unit=3 THEN short_msg('Stichprobe:',0); add_msg(' '+hexstr(dummy^.pg,3), style); END; BEGIN hurricane; redraw_queue(-1); { Seitensuche freimachen } { Suchfilter festlegen: } FOR i := $100 TO $8FF DO wanted[i] := (mode=0); IF mode=1 THEN FOR i := 100 TO 899 DO wanted[make_bcd(i)] := True; IF mode=2 THEN BEGIN anz := 0; FOR i := 0 TO queued-1 DO BEGIN j := firstinq + i; IF j>qlen THEN j := 1; j := queue[j].pg; IF (j IN [$100..$8FF]) AND NOT wanted[j] THEN BEGIN wanted[j] := True; Inc(anz); END; END; short_msg(IntStr(anz)+' gesuchte Seitennummern',0); END; New(dummy); anz := 0; neu := 0; REPEAT redraw := (root=Nil); lastq := queued; FOR i := 0 TO 2 DO sperren(i); anfordern(3,$100,0,%000); waitforpg(3); getpage(3,dummy,False); parmode := (dummy^.cbits AND PF_SERMAG)=0; IF parmode THEN BEGIN { magazinparallele Sendefolge ;-\ } FOR i := 3 DOWNTO -1 DO IF NOT timeout THEN BEGIN { indirektes Sperren von (i+1): } IF i>-1 THEN anfordern(i,dummy^.pg,0,%100) { Die Seite in (i+2) ist bereits komplett und stabil: } IF i<2 THEN einlesen(i+2); { jetzt auf die zuletzt angeforderte Seite warten: } IF i>-1 THEN waitforpg(i); END END ELSE BEGIN { normale, magazinserielle Sendefolge } FOR i := 2 DOWNTO 0 DO IF NOT timeout THEN BEGIN { (i+1) sperren und auf die nächste Seite warten: } anfordern(i,$100,0,%000); waitforpg(i); END; { alle kompletten Seiten einlesen: } IF NOT timeout THEN FOR i := 3 DOWNTO 1 DO einlesen(i); END; IF redraw AND NOT timeout THEN writepage(thispage, True); IF queued vorgegebenen Priorität } CONST interleave=10; VAR i,j,n,level: Integer; pri: ARRAY[0..17] OF Char; BEGIN pri := '-KABCDEFHGJI-----'; FOR level := 1 TO toplevel DO FOR i := 0 TO interleave-1 DO FOR j := 0 TO 799 DIV interleave DO BEGIN n := 100 + j*interleave + i; IF (n<900) THEN BEGIN IF Ord(pri[topcode[pg0^.chars[n-60]]])-64=level THEN add_job(IntStr(n),True); { nach absteigender Priorität } END; END; redraw_queue(-1); END; PROCEDURE getconfig{(nr: Integer)}; VAR datei: Text; sender, zeile, name: str80; save_fifo: Boolean; t,block: Integer; BEGIN gethead(name); name2dosname(name,sender); name := configpath+sender; Reset(datei,name); IF IOResult<>0 THEN BEGIN short_msg('keine Auswahl für "'+sender+'" vorhanden',2); add_job('100',False); redraw_queue(-1); Exit; END; Buffer(datei,500); short_msg('hole ',0); IF nr>1 THEN add_msg(IntStr(nr)+'. ',0); add_msg('Seitenauswahl für "'+sender+'"',0); block := 1; save_fifo := fifo; fifo := True; WHILE NOT EoF(datei) DO BEGIN ReadLn(datei,zeile); t := Length(zeile); WHILE t>0 DO BEGIN IF zeile[t]=' ' THEN zeile[t] := #0; Dec(t); END; IF zeile='' THEN Inc(block) { Leerzeile trennt Blöcke } ELSE IF block=nr THEN add_job(zeile,True); END; Close(datei); fifo := save_fifo; redraw_queue(-1); END; LIBRARY DosBase: { Include-Files nein danke } -222 : FUNCTION Execute(D1: Str; D2,D3: Long): Boolean; END; FUNCTION ed_config{(hint: p_onepage): Boolean}; { Seitenvorauswahl für den aktuellen Sender editieren } VAR fenster: Text; s,datei: Str80; i: Integer; BEGIN s[25] := #0; IF hint=Nil THEN gethead(s) ELSE FOR i := 1 TO 24 DO BEGIN s[i] := Chr(hint^.chars[i+7]); IF s[i]<' ' THEN s[i] := ' '; END; name2dosname(s,datei); showscreen(0); Reset(fenster,'CON:100/100/440/80/VT-Ausgabefenster'); s := editor + configpath + datei; ed_config := Execute(s,0,FileHandle(fenster)); Close(fenster); showscreen(2); END; FUNCTION ed_stations{: Boolean}; { Editoraufruf für die ".stations"-Liste } VAR fenster: Text; s: Str80; BEGIN showscreen(0); Reset(fenster,'CON:100/100/440/80/VT-Ausgabefenster'); s := editor + configpath + '.stations'; ed_stations := Execute(s,0,FileHandle(fenster)); Close(fenster); showscreen(2); END; PROCEDURE dump_numbers; { Seitennummern ins Clipboard schreiben, Hilfe beim Ändern der Vorauswahlen } VAR anz,nextnr: Integer; hilf: p_onepage; ok: Boolean; s: str80; BEGIN IF root=Nil THEN Exit; anz := 0; hilf := root; WHILE hilf<>Nil DO BEGIN IF hilf^.next=Nil THEN nextnr := -1 ELSE nextnr := hilf^.next^.pg; IF (hilf^.pg<$900) AND (hilf^.pg<>nextnr) THEN Inc(anz); hilf := hilf^.next; END; start_clip(4*anz); hilf := root; WHILE hilf<>Nil DO BEGIN IF hilf^.next=Nil THEN nextnr := -1 ELSE nextnr := hilf^.next^.pg; IF (hilf^.pg<$900) AND (hilf^.pg<>nextnr) THEN BEGIN s := hexstr(hilf^.pg,3)+#10; clip_it(s,4); END; hilf := hilf^.next; END; end_clip; END; PROCEDURE dump_title{(seite: p_onepage)}; { Sendernamen ins Clipboard schreiben } VAR s: str80; i: Integer; BEGIN start_clip(24); IF seite=Nil THEN gethead(s) ELSE FOR i := 1 TO 24 DO BEGIN s[i] := Chr(seite^.chars[i+7]); IF s[i]<' ' THEN s[i] := ' '; END; s[25] := #0; clip_it(s,24); end_clip; END; BEGIN { Initialisierungen } editor := 'c:Ed '; { Editor für configs } toplevel := 4; { nur Programm- und Blockseiten } maxwait := 80; burst := 0; shuffle := 20; END.