UNIT jobs; {$project vt } { Job-Verwaltung zum Programm VideoText } INTERFACE; FROM vt USES datei; VAR editor,configpath: str80; toplevel: Integer; active: Byte; { aktive Jobs in der Seitensuche } maxwait, burst,shuffle: Integer; i2c_snooze: Boolean; PROCEDURE sleep; PROCEDURE wakeup; PROCEDURE kill_queue; PROCEDURE handle_queue; PROCEDURE handle_jobs; PROCEDURE attempt_input(job: Integer); PROCEDURE add_job(entry: str80; blind: Boolean); PROCEDURE kill_job(nr: Integer); PROCEDURE cancel_job(entry: str80); PROCEDURE hurricane; PROCEDURE page_grabber(filter: Boolean); PROCEDURE topgrab(pg0: p_onepage); PROCEDURE getconfig(nr: Integer); FUNCTION edconfig(nr: Integer): Boolean; PROCEDURE dump_numbers; { ---------------------------------------------------------------------- } IMPLEMENTATION; {$ opt q,s+,i+} { keine Laufzeitprüfungen außer Stack und Feldindizes } CONST SERMAG = $0800; { C11 } RENEW = $0100; { C8 } STITLE = $0040; { C6 } HEADLN = $0020; { C5 } VAR bedtime: zeiteintrag; 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,sp,%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 BEGIN aktspeicher := thisjob; display_select(aktspeicher); END; 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 rausschmeisser; { Prüfen, ob ein Job wegen Zeitüberschreitung gestrichen werden kann. } { Wenn der Job allerdings so lange wartet, weil er sich auf eine einzelne } { Unterseite bezieht, ist ihm verziehen und er wird lediglich ans Ende der } { Warteschlange gesetzt. Und für festgehaltene Seitennummern findet eine } { Prüfung auf Zeitüberschreitung gar nicht erst statt. } VAR i, j: Integer; jetzt: zeiteintrag; 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 { keine "festgehaltenen" Seiten! } IF sp IN [0,-1] THEN BEGIN { einfache Seitennummer streichen } pg := 0; sperren(j); redraw_queue(j); END ELSE IF queued>0 THEN BEGIN { Unterseitenanforderung nur hintenanstellen } requeue(j,True); redraw_queue(-1); 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. } { Das dürfte allerdings kaum vorkommen, da der CCT ausdrücklich auf } { die eine Unterseite programmiert wurde. } 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=-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 SERMAG)=0 THEN wartezeit := shuffle ELSE wartezeit := burst; END ELSE anfordern(j,pg,sp,%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=-2) OR (sp=-3) THEN erledigt := True; Dispose(dummy); 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: } IF i2c_snooze THEN busy_pointer; { 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 i2c_snooze THEN normal_pointer; 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 i2c_snooze THEN normal_pointer; 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 RENEW<>0)) AND (seite^.cbits AND STITLE=0) AND (seite^.sp=0); { Untertitel und Mehrfachseiten aber ausgenommen! } { bildschirmüberwachte Seite anzeigen: } IF (seite=thispage) OR exciting THEN BEGIN mainline; IF exciting THEN showscreen(True); IF seite<>thispage THEN BEGIN Write('neuer Inhalt S. ',hexstr(pg,3),'!'); writepage(seite,True); mainline; Write('bitte Leertaste dr}cken'); END ELSE writepage(seite,True); END; { dateiüberwachte Seite abspeichern: } IF sp=-3 THEN IF (sp_count=1) OR (seite^.cbits AND RENEW<>0) THEN BEGIN sleep; IF save_action(seite,1)=0 THEN BEGIN { nach einmal genehmigtem Überschreiben auf Anhängen umschalten: } overwrite := False; fileinfo; END ELSE sp_count := 0; { nach fehlgeschlagenem Speichern } { sofort beim nächsten Mal wieder versuchen lassen } wakeup; END ELSE mainline; holen := False; { beendet auch "Schonfrist" für erledigte Jobs } anfordern(job,pg,sp,%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]) 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 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; s: str80; ok: Boolean; BEGIN i := Pos('-',entry); j := Pos('/',entry); IF i > 0 THEN BEGIN page := hexval(Copy(entry,1,i-1)); Val(Copy(entry,i+1,Length(entry)-i),subpage,i); { Anzahl nicht als BCD! } subpage := -10-subpage; END ELSE IF j > 0 THEN BEGIN page := hexval(Copy(entry,1,j-1)); subpage := hexval(Copy(entry,j+1,Length(entry)-j)); IF entry[j+1]='*' THEN subpage := -1; IF entry[j+1]='.' THEN subpage := -2; IF entry[j+1]='!' THEN subpage := -3; END ELSE BEGIN page := hexval(entry); subpage := 0; END; 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{(entry: str80)}; { Als Erleichterung gegenüber kill_job() wird nicht die Position in der } { Warteschlange sondern der 'Name' des Jobs angegeben. } VAR page,j: Integer; BEGIN page := hexval(Copy(entry,1,3)); 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; PROCEDURE page_grabber{(filter: Boolean)}; { Rechenzeitintensive Variante der Seitensuche: alle Seiten einlesen, wie } { sie kommen. Für =True werden nur Seiten mit rein dezimaler } { Seitennummer gelesen, Pseudoseiten also herausgefiltert. } { 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,mag,anz,neu: Integer; seite,dummy: p_onepage; timeout,parmode: Boolean; PROCEDURE waitforpg(unit: Integer); { max. 2 Sekunde auf das Eintreffen einer Seite warten } VAR t0,t: zeiteintrag; BEGIN uhrzeit(t0); REPEAT uhrzeit(t); timeout := diff_time(t0,t)>100; UNTIL seite_da(unit) OR timeout; END; PROCEDURE einlesen(unit: Integer); { neue Seite einlesen und einreihen } BEGIN getpage(unit,dummy,False); IF (make_bcd(get_bcd(dummy^.pg))=dummy^.pg) OR NOT filter THEN BEGIN Inc(anz); seite := hunt_in_list(dummy^.pg,dummy^.sp,True); IF seite=Nil THEN BEGIN New(seite); Inc(neu); getpage(unit,seite,True); add_sp_number(seite); ins_to_list(seite); END; END; END; BEGIN New(dummy); anz := 0; neu := 0; hurricane; redraw_queue(-1); { Seitensuche freimachen } REPEAT FOR i := 0 TO 2 DO sperren(i); anfordern(3,$100,0,%000); waitforpg(3); getpage(3,dummy,False); parmode := (dummy^.cbits AND 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; mainline; Write(anz,' Seiten gefunden, ',neu,' gelesen'); event_scan; UNTIL newevent OR timeout; IF timeout THEN BEGIN mainline; Write('keine neuen Seiten - Abbruch'); END; Dispose(dummy); END; PROCEDURE topgrab{(pg0: p_onepage)}; { alle laut TOP-Text verfügbaren Seiten anfordern, allerdings nur bis zu } { der durch 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; is_header, found, anything, save_fifo: Boolean; t: Integer; BEGIN IF activejobs[0].pg=0 THEN BEGIN anfordern(0,$100,0,%000); t := 50; { max. 1 sec warten! } REPEAT Delay(1); Dec(t) UNTIL seite_da(0) or (t=0); END; gethead(0,sender); IF activejobs[0].pg=0 THEN sperren(0); IF nr=2 THEN name := configpath+'VT2.config' ELSE name := configpath+'VT.config'; Reset(datei,name); IF IOResult<>0 THEN BEGIN mainline; Write(#155'2m"',name,'" nicht gefunden!'); add_job('100',False); redraw_queue(-1); Exit; END; Buffer(datei,500); found := False; anything := False; is_header := True; 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 ELSE t := 1; Dec(t); END; IF zeile='' THEN is_header := True { auf eine Leerzeile folgt ein Titel } ELSE BEGIN IF is_header THEN BEGIN found := (Pos(zeile,sender)>0); IF found THEN BEGIN mainline; Write('hole '); IF nr>1 THEN Write(nr,'. '); Write('Seitenauswahl f}r "',zeile,'"'); anything := True; END; END ELSE IF found THEN add_job(zeile,True); is_header := False; END; END; IF NOT anything THEN BEGIN Write('unbekannter Sender: "',Copy(sender,5,10),'"'); add_job('100',False); END; Close(datei); fifo := save_fifo; redraw_queue(-1); END; FUNCTION edconfig{(nr: Integer): Boolean}; VAR fenster: Text; s: Str80; LIBRARY DosBase: { Include-Files nein danke } -222 : FUNCTION Execute(D1: Str; D2,D3: Long): Boolean; END; BEGIN showscreen(False); Reset(fenster,'CON:100/100/440/80/VT-Ausgabefenster'); IF nr=2 THEN s := editor + configpath + 'VT2.config' ELSE s := editor + configpath + 'VT.config'; edconfig := Execute(s,0,FileHandle(fenster)); Close(fenster); showscreen(True); END; PROCEDURE dump_numbers; { Sendername und Seitennummern ins Clipboard schreiben, Hilfe beim Erstellen } { der config-Dateien } VAR anz,nextnr,i: 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(26+4*anz); FOR i := 2 TO 25 DO BEGIN s[i] := Chr(root^.chars[i+6]); IF s[i]<' ' THEN s[i] := ' '; END; s[1] := #10; s[26] := #10; s[27] := #0; clip_it(s,26); 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; BEGIN { Initialisierungen } editor := 'c:Ed '; { Editor für configs } configpath := ''; toplevel := 4; { nur Programm- und Blockseiten } maxwait := 80; burst := 0; shuffle := 20; i2c_snooze := False; { kein Busy-Pointer beim Lesen von Seiten! } END.