home *** CD-ROM | disk | FTP | other *** search
/ The Best of Mecomp Multimedia 1 / Mecomp-CD.iso / amiga / tools / misc / videotext5.41 / src / jobs.p < prev    next >
Encoding:
Text File  |  1997-05-02  |  25.8 KB  |  761 lines

  1. UNIT jobs; {$project vt }
  2. { Job-Verwaltung zum Programm VideoText }
  3.  
  4. INTERFACE; FROM vt USES datei;
  5.  
  6. VAR editor: str80;
  7.     toplevel: Integer;
  8.     active: Byte; { aktive Jobs in der Seitensuche }
  9.     maxwait, burst,shuffle: Integer;
  10.  
  11. PROCEDURE uhrzeit(VAR zeit: zeiteintrag);
  12. FUNCTION diff_time(alt, neu: zeiteintrag): Long;
  13. PROCEDURE sleep;
  14. PROCEDURE wakeup;
  15. PROCEDURE kill_queue;
  16. PROCEDURE handle_queue;
  17. PROCEDURE handle_jobs;
  18. PROCEDURE attempt_input(job: Integer);
  19. PROCEDURE pgstr2numbers(s: str80; VAR pg, sp: Integer);
  20. PROCEDURE add_job(entry: str80; blind: Boolean);
  21. PROCEDURE kill_job(nr: Integer);
  22. PROCEDURE cancel_job(page: Integer);
  23. PROCEDURE hurricane;
  24. FUNCTION do_retry: Integer;
  25. PROCEDURE page_grabber(mode: Byte);
  26. PROCEDURE topgrab(pg0: p_onepage);
  27. PROCEDURE getconfig(nr: Integer);
  28. FUNCTION ed_config(hint: p_onepage): Boolean;
  29. FUNCTION ed_stations: Boolean;
  30. PROCEDURE dump_numbers;
  31. PROCEDURE dump_title(seite: p_onepage);
  32.  
  33. { ---------------------------------------------------------------------- }
  34.  
  35. IMPLEMENTATION;
  36.  
  37. {$ opt q,s+,i+} { keine Laufzeitprüfungen außer Stack und Feldindizes }
  38.  
  39. VAR bedtime: zeiteintrag;
  40.     wanted: ARRAY [$100..$8FF] OF Boolean; STATIC;
  41.  
  42. PROCEDURE uhrzeit{(VAR zeit: zeiteintrag)};
  43. BEGIN
  44.   telltime(zeit.tage,zeit.min,zeit.tics);
  45. END;
  46.  
  47. PROCEDURE add_time(delta: zeiteintrag; VAR zeit: zeiteintrag);
  48. BEGIN
  49.   IF zeit.tics + delta.tics>=3000 THEN Inc(zeit.min);
  50.   zeit.tics := (zeit.tics + delta.tics) MOD 3000;
  51.   IF zeit.min + delta.min>=1440 THEN Inc(zeit.tage);
  52.   zeit.min := (zeit.min + delta.min) MOD 1440;
  53.   zeit.tage := zeit.tage + delta.tage;
  54. END;
  55.  
  56. PROCEDURE sub_time(delta: zeiteintrag; VAR zeit: zeiteintrag);
  57. BEGIN
  58.   IF zeit.tics - delta.tics<0 THEN Dec(zeit.min);
  59.   zeit.tics := (zeit.tics - delta.tics + 3000) MOD 3000;
  60.   IF zeit.min - delta.min<0 THEN Dec(zeit.tage);
  61.   zeit.min := (zeit.min - delta.min + 1440) MOD 1440;
  62.   zeit.tage := zeit.tage - delta.tage;
  63. END;
  64.  
  65. FUNCTION diff_time{(alt, neu: zeiteintrag): Long};
  66. { liefert die Differenz zwischen zwei Zeitpunkten in Ticks (1/50-Sekunden) }
  67. BEGIN
  68.   diff_time := neu.tics - alt.tics + 3000 * ( (neu.min - alt.min)
  69.                + 1440 * (neu.tage - alt.tage) );
  70. END;
  71.  
  72. PROCEDURE sleep;
  73. { wird vor Unterbrechung der Hauptschleife (z. B. durch FileRequester) }
  74. { aufgerufen }
  75. BEGIN
  76.   uhrzeit(bedtime);
  77. END;
  78.  
  79. PROCEDURE wakeup;
  80. { Verhindert in Zusammenarbeit mit sleep, daß Zeiten, während derer der }
  81. { VT-Decoder gar nicht abgefragt wird, zum Löschen von Jobs wegen }
  82. { Zeitüberschreitung führen. }
  83. VAR delta: zeiteintrag;
  84.     j: Integer;
  85. BEGIN
  86.   uhrzeit(delta);
  87.   sub_time(bedtime,delta);
  88.   FOR j := 0 TO maxactive-1 DO
  89.     add_time(delta,activejobs[j].lastaction);
  90. END;
  91.  
  92. PROCEDURE kill_queue;
  93. VAR i: Integer;
  94. BEGIN
  95.   queued := 0;
  96.   IF thisjob<0 THEN thisjob := 0;
  97.   FOR i := 0 TO maxactive-1 DO BEGIN
  98.     activejobs[i].pg := 0; sperren(i);
  99.   END;
  100. END;
  101.  
  102. PROCEDURE count_them;
  103. { durchzählen, wer in der Seitensuche alles bedient werden will: }
  104. VAR j: Integer;
  105. BEGIN
  106.   active := 0;
  107.   FOR j := 0 TO maxactive-1 DO
  108.     IF (activejobs[j].pg>0) THEN Inc(active);
  109. END;
  110.  
  111. PROCEDURE handle_queue;
  112. { Verwaltet das Aufrücken wartender Jobs. }
  113. { Jobs mit unbestimmter Unterseitennummer, also mit /0, /*, /., /! können }
  114. { aktive Jobs mit gleicher Seitennummer aus der Seitensuche verdrängen }
  115. VAR i,j,killer,moved: Integer;
  116. BEGIN
  117.   moved := 0;
  118.   REPEAT
  119.     j := -1;
  120.     IF queued>0 THEN BEGIN
  121.       { Soll ein aktiver Job verdrängt werden? }
  122.       IF queue[firstinq].sp<1 THEN
  123.         FOR i := 0 TO maxactive-1 DO
  124.           IF activejobs[i].pg=queue[firstinq].pg THEN j := i;
  125.       { Oder ist ein Platz in der Seitensuche frei? }
  126.       IF j<0 THEN
  127.         FOR i := maxactive-1 DOWNTO 0 DO
  128.           IF activejobs[i].pg=0 THEN j := i;
  129.     END;
  130.     IF j>=0 THEN BEGIN
  131.       { Empfangseinheit <j> mit wartendem Job belegen }
  132.       { Ein wartender Job besteht nur aus Seiten- und Unterseitennummer, }
  133.       { jetzt kommen eine Menge Informationen dazu. }
  134.       WITH activejobs[j] DO BEGIN
  135.         pg := queue[firstinq].pg; sp := queue[firstinq].sp;
  136.         sp_count := 0; sp_max := 0;
  137.         holen := False; erledigt := False;
  138.         FOR i := 0 TO maxsubpage DO sp_check[i] := False;
  139.         uhrzeit(lastaction);
  140.         anfordern(j,pg,0,%111);
  141.       END;
  142.       IF i2c_status<>0 THEN BEGIN  { Oh Mann! Dummer I²C-Bus! }
  143.         activejobs[j].pg := 0;   { Kommando zurück }
  144.         j := -1;  { hier ist nichts mehr zu holen }
  145.       END ELSE BEGIN
  146.         { Warteschlange aufrücken: }
  147.         Dec(queued); Inc(firstinq); IF firstinq>qlen THEN firstinq := 1;
  148.         { Auswahlzeiger des Benutzers dem Aufrücken entsprechend nachführen: }
  149.         IF thisjob=-1 THEN thisjob := j
  150.           ELSE IF thisjob<0 THEN Inc(thisjob);
  151.         IF thisjob>=0 THEN
  152.           display_select(thisjob);
  153.         Inc(moved);
  154.       END;
  155.     END;
  156.   UNTIL j=-1;
  157.   IF moved>0 THEN redraw_queue(-1);
  158.   count_them;
  159. END;
  160.  
  161. PROCEDURE requeue(i: Integer; fifo: Boolean);
  162. { einen aktiven Job in die Warteschlange zurückstellen }
  163. VAR j: Integer;
  164. BEGIN
  165.   IF (queued<qlen) AND (activejobs[i].pg>0) THEN BEGIN
  166.     IF fifo THEN BEGIN
  167.       j := firstinq+queued; IF j>qlen THEN j := 1;
  168.     END ELSE BEGIN 
  169.       Dec(firstinq); IF firstinq=0 THEN firstinq := qlen; j := firstinq;
  170.     END;
  171.     Inc(queued);
  172.     queue[j].pg := activejobs[i].pg; queue[j].sp := activejobs[i].sp;
  173.   END;
  174.   activejobs[i].pg := 0; sperren(i);
  175. END;
  176.  
  177. PROCEDURE rearrange;
  178. { ersten und zweiten Platz der Warteschlange vertauschen }
  179. VAR i, j, hilf: Integer;
  180. BEGIN
  181.   IF queued>1 THEN BEGIN
  182.     i := firstinq; j := i+1; IF j>qlen THEN j := 1;
  183.     hilf := queue[i].pg; queue[i].pg := queue[j].pg; queue[j].pg := hilf;
  184.     hilf := queue[i].sp; queue[i].sp := queue[j].sp; queue[j].sp := hilf;
  185.   END;
  186. END;
  187.  
  188. PROCEDURE rausschmeisser;
  189. { Prüfen, ob ein Job wegen Zeitüberschreitung gestrichen werden kann. }
  190. { Passend zum gelöschten Job wird anschließend eine Dummy-Seite mit }
  191. { teilnahmsvoller Meldung in die Liste eingereiht. }
  192. VAR i, j: Integer;
  193.     jetzt: zeiteintrag;
  194.     seite: p_onepage;
  195. BEGIN
  196.   uhrzeit(jetzt);
  197.   FOR j := 0 TO maxactive-1 DO WITH activejobs[j] DO
  198.     IF (pg<>0) AND (diff_time(lastaction,jetzt) > 50*maxwait)
  199.     AND (sp>-2) THEN BEGIN { aber keine "festgehaltenen" Seiten! }
  200.       i := sp; IF i<0 THEN i := 0;
  201.       seite := hunt_in_list(pg,i,True);
  202.       IF seite=Nil THEN BEGIN
  203.         New(seite);
  204.         seite^.pg := pg; seite^.sp := i; init_page(seite);
  205.         ins_to_list(seite); update_list(seite,1);
  206.       END ELSE BEGIN
  207.         seite^.pg := pg; seite^.sp := i; init_page(seite);
  208.       END;
  209.       write_to_page(0,2,' Seite '+hexstr(pg,3)
  210.                     +' nicht gefunden - Sorry',3,1,seite);
  211.       write_to_page(0,3,'  Suche nach '+IntStr(diff_time(lastaction,
  212.                     jetzt) DIV 50)+' Sek. abgebrochen',4,6,seite);
  213.       write_to_page(0,5,'       Nochmal anfordern: f8',3,1,seite);
  214.       write_to_page(0,6,'  oder diese Seite wegwerfen: Del',4,6,seite);
  215.       IF thispage=seite THEN
  216.         writepage(seite,True);
  217.       pg := 0; sperren(j); redraw_queue(j);
  218.     END;
  219.   count_them;
  220. END;
  221.  
  222. PROCEDURE handle_jobs;
  223. { Überprüft, ob in einem der Empfangskreise eine Seite eingetroffen ist, und }
  224. { wenn ja, ob sie aufgrund ihrer Unterseitennummer überhaupt eingelesen }
  225. { werden muß. Es wird auch entschieden, ob der Job durch die eingetroffene }
  226. { Seite erledigt ist. Kriterium für 'erledigt': }
  227. { Ein Job mit sp>0 ist erledigt, sobald die eine angeforderte Unterseite }
  228. { da ist. Ein Job mit sp=0 ist erst dann erledigt, wenn alle seine }
  229. { Unterseiten eingelesen wurden. Wann das ist, läßt sich nur raten, aber }
  230. { ganz gut raten. Und es gibt noch einige Sonderfälle mit sp<0 ... }
  231. VAR j: Integer;
  232.     dummy: p_onepage;
  233.     sp_decval: Integer;
  234. BEGIN
  235.   rausschmeisser;
  236.   { Schauen, ob irgendwo das Eintreffen einer Kopfzeile gemeldet wurde: }
  237.   FOR j := 0 TO maxactive-1 DO WITH activejobs[j] DO
  238.     IF (pg>0) AND NOT holen THEN IF seite_da(j) THEN BEGIN
  239.       New(dummy);
  240.       uhrzeit(lastaction);
  241.       getpage(j,dummy,False); { *nur* Status und Seitennummer holen }
  242.       akt_sp := dummy^.sp;
  243.       sp_decval := get_bcd(akt_sp);
  244.       { *** Schauen, ob die Seite eingelesen werden muß. Gründe, weswegen }
  245.       {   man eine Seite evtl. nicht haben will: }
  246.       { 1.: Unterseite wurde bereits eingelesen. }
  247.       {   (Bei zu großen Unterseitennummern kann das nur über ein etwas }
  248.       {   armseliges Hilfskriterium festgestellt werden.) }
  249.       IF (sp_decval<=maxsubpage) THEN holen := NOT sp_check[sp_decval]
  250.         ELSE holen := (akt_sp>sp_max);
  251.       { 2.: Nur eine Unterseite war angefordert, und zwar nicht diese. }
  252.       IF sp>0 THEN holen := (akt_sp=sp);
  253.       { Selbstnumerierende Unterseiten werden blind alle eingelesen, bis }
  254.       { der Job erledigt ist: }
  255.       IF sp<=-10 THEN BEGIN
  256.         holen := True; akt_sp := make_bcd(sp_count+1);
  257.         IF sp IN [-10,-11] THEN akt_sp := 0;
  258.         sp_decval := get_bcd(akt_sp);
  259.       END;
  260.       IF holen THEN BEGIN
  261.         { *** Unterseitenverwaltung aktualisieren: }
  262.         Inc(sp_count);
  263.         IF (sp_decval<=maxsubpage) THEN  sp_check[sp_decval] := True;
  264.         IF akt_sp>sp_max  THEN sp_max := akt_sp;
  265.         redraw_queue(j);
  266.         { *** Schauen, ob magazinserielle oder -gemischte Übertragung }
  267.         {   vorliegt und danach die Wartezeit festlegen: }
  268.         IF (dummy^.cbits AND PF_SERMAG)=0 THEN
  269.           wartezeit := shuffle ELSE wartezeit := burst;
  270.       END ELSE
  271.         anfordern(j,pg,0,%111); { blöde Unterseite, Suche fortsetzen }
  272.       { *** Prüfen, ob der Job durch die eingetroffene Seite erledigt ist. }
  273.       {   Das geht z. B. durch Unterseite 0 (= einzige Unterseite). }
  274.       {   auf keinen Fall aber durch eine Unterseite mit der bislang }
  275.       {   höchsten Nummer. }
  276.       IF sp_check[0] THEN
  277.         erledigt := sp_count>get_bcd(sp_max)
  278.       ELSE IF akt_sp<sp_max THEN
  279.         erledigt := sp_count=get_bcd(sp_max);
  280.       { Auch möglich: die einzig geforderte Unterseite ist da. }
  281.       IF ((sp>0) OR (sp=-1)) AND holen THEN
  282.         erledigt := True;
  283.       { Oder es sind genauso viele selbstnumerierende Unterseiten }
  284.       { eingetroffen, wie angefordert waren. }
  285.       IF (sp<-10) THEN
  286.         erledigt := (sp_count=-sp-10);
  287.       { überwachte Seiten sind aus kosmetischen Gründen immer "erledigt": }
  288.       IF sp IN [-2,-3,-10] THEN
  289.         erledigt := True;
  290.       Dispose(dummy);
  291.       { Evtl. noch eine Vergeltungsmaßnahme: einzelne Unterseiten- }
  292.       { anforderung, zu der eine *falsche* Unterseite eingetroffen ist, }
  293.       { muß eine andere vorbeilassen: }
  294.       IF (sp>0) AND NOT holen AND (queued>0) THEN BEGIN
  295.         requeue(j,False); rearrange; redraw_queue(-1);
  296.       END;
  297.     END;
  298. END;
  299.  
  300. PROCEDURE attempt_input{(job: Integer)};
  301. { Das Einlesen geschieht in einem zweiten Schritt, da nach Eintreffen der }
  302. { Kopfzeile erst eine Weile gewartet werden muß. }
  303. { Evtl. wird die Seite auch gleich ausgegeben: auf dem Bildschirm, falls }
  304. { <thisjob> auf den zugehörigen Job zeigt oder wenn eine festgehaltene }
  305. { Seite aktualisiert wurde; in die Ausgabedatei, falls es eine zu }
  306. { protokollierende Seite war. }
  307. { Jobs, die nach diesem Einlesen erledigt sind, wurden bereits entsprechend }
  308. { gekennzeichnet und werden aus der Liste gestrichen. }
  309. VAR dummy,seite: p_onepage;
  310.     jetzt: zeiteintrag;
  311.     exciting: Boolean;
  312.     i: Integer;
  313. BEGIN
  314.   { Prüfen, ob die Wartezeit für eine einzulesende Seite um ist: }
  315.   WITH activejobs[job] DO
  316.     IF (pg>0) AND holen THEN BEGIN
  317.       uhrzeit(jetzt);
  318.       IF diff_time(lastaction,jetzt) >= wartezeit THEN BEGIN
  319.         { Seite einlesen: }
  320.         { Ist bereits eine alte Version dieser Seite in der Liste, die dann }
  321.         { lediglich überschrieben werden müßte? }
  322.         seite := hunt_in_list(pg,akt_sp,True);
  323.         IF seite=Nil THEN BEGIN
  324.           New(seite);
  325.           getpage(job,seite,True);
  326.           IF sp<=-10 THEN seite^.sp := akt_sp; { selbstnumerierende Seite! }
  327.           add_sp_number(seite);
  328.           IF i2c_status<>0 THEN BEGIN Dispose(seite); Exit; END;
  329.           ins_to_list(seite);
  330.           update_list(seite,1);
  331.         END ELSE BEGIN
  332.           getpage(job,seite,True);
  333.           IF sp<=-10 THEN seite^.sp := akt_sp; { selbstnumerierende Seite! }
  334.           add_sp_number(seite);
  335.           IF i2c_status<>0 THEN Exit;
  336.           IF seite<>thispage THEN update_list(seite,0);
  337.         END;
  338.         { bildschirmüberwachte Seiten sind interessant, wenn sie das erste }
  339.         { Mal eintreffen oder wenn sich der Inhalt geändert hat: }
  340.         exciting := (sp=-2) AND ((sp_count=1) OR (seite^.cbits AND PF_RENEW<>0))
  341.             AND (seite^.cbits AND PF_STITLE=0) AND (seite^.sp=0);
  342.         { Untertitel und Mehrfachseiten aber ausgenommen! }
  343.         { bildschirmüberwachte Seite anzeigen: }
  344.         IF (seite=thispage) OR exciting THEN BEGIN
  345.           IF exciting THEN showscreen(2);
  346.           IF seite<>thispage THEN BEGIN
  347.             short_msg('neuer Inhalt S. '+hexstr(pg,3)+'!',0);
  348.             writepage(seite,True);
  349.             short_msg('bitte Leertaste drücken',0);
  350.           END ELSE
  351.             writepage(seite,True);
  352.         END;
  353.         { dateiüberwachte Seite abspeichern: }
  354.         IF sp=-3 THEN
  355.           IF (sp_count=1) OR (seite^.cbits AND PF_RENEW<>0) THEN BEGIN
  356.             sleep; 
  357.             IF save_action(seite,1)<>0 THEN 
  358.               { nach fehlgeschlagenem Speichern sofort neuen Versuch: }
  359.               sp_count := 0;
  360.             wakeup;
  361.           END ELSE
  362.             short_msg('',0);
  363.         holen := False;  { beendet auch "Schonfrist" für erledigte Jobs }
  364.         anfordern(job,pg,0,%111);   { um PBLF wieder zu setzen }
  365.       END;
  366.     END;
  367.   { Erledigten (und eingelesenen) Job löschen: }
  368.   WITH activejobs[job] DO
  369.     IF (pg>0) AND erledigt AND NOT holen THEN BEGIN
  370.       IF (sp IN [-2,-3,-10]) THEN BEGIN   { Sonderfälle: niemals erledigt }
  371.         { nur die Zähler zurücksetzen, außer sp_count }
  372.         sp_max := 0; erledigt := False;
  373.         FOR i := 0 TO maxsubpage DO sp_check[i] := False;
  374.       END ELSE BEGIN
  375.         pg := 0; sperren(job);  { löschen }
  376.       END;
  377.       redraw_queue(job);
  378.     END;
  379.   count_them;
  380. END;
  381.  
  382. PROCEDURE pgstr2numbers{(s: str80; VAR pg, sp: Integer)};
  383. VAR i,j,k: Integer;
  384. BEGIN
  385.   i := Pos('/',s);
  386.   j := Pos('*',s);  IF j = 0 THEN  j := Pos('-',s);   { zwei Varianten ;-| }
  387.   k := Length(s);
  388.   IF i > 0 THEN BEGIN
  389.     pg := hexval(Copy(s,1,i-1));
  390.     sp := hexval(Copy(s,i+1,k-i));
  391.     IF s[i+1]='*' THEN sp := -1;
  392.     IF s[i+1]='.' THEN sp := -2;
  393.     IF s[i+1]='!' THEN sp := -3;
  394.   END ELSE IF j > 0 THEN BEGIN
  395.     pg := hexval(Copy(s,1,j-1));
  396.     Val(Copy(s,j+1,k-j),sp,j); { "*"-Anzahl nicht als BCD! }
  397.     sp := -10-sp;
  398.   END ELSE BEGIN
  399.     pg := hexval(s);
  400.     sp := 0;
  401.   END;
  402. END;
  403.  
  404. PROCEDURE add_job{(entry: Str80; blind: Boolean)};
  405. { Eine Eingabe, die eine Seitennummer darstellt (oder auch nicht), in die }
  406. { Warteschlange einzureihen versuchen. }
  407. { Bei blind=False wird noch überprüft, ob sich vielleicht bereits ein }
  408. { identischer Job in der Seitensuche befindet. }
  409. { Anschließend zeigt <thisjob> auf die neu besetzte Stelle. }
  410. VAR i,j,page,subpage: Integer;
  411.     ok: Boolean;
  412. BEGIN
  413.   pgstr2numbers(entry, page, subpage);
  414.   ok := (page>=$100) AND (page<$900);
  415.   { evtl. weitere Einschränkung: mit bereits vorhandenen Jobs vergleichen }
  416.   { und keinen Job zulassen, der ein Verdrängen bewirken würde }
  417.   IF NOT blind THEN BEGIN
  418.     FOR j := 0 TO maxactive-1 DO
  419.       IF (activejobs[j].pg=page) AND (subpage<1) THEN ok := False;
  420.     FOR j := 1 TO queued DO BEGIN
  421.       i := (firstinq + j - 2) MOD qlen + 1;
  422.       IF (queue[i].pg=page) AND (subpage<1) THEN ok := False;
  423.     END;
  424.   END;
  425.   IF ok AND (queued<qlen) THEN BEGIN
  426.     Inc(queued);
  427.     IF fifo THEN BEGIN
  428.       j := firstinq+queued-1; IF j>qlen THEN j := 1;
  429.       thisjob := -queued;
  430.     END ELSE BEGIN
  431.       Dec(firstinq); IF firstinq=0 THEN firstinq := qlen; j := firstinq;
  432.       thisjob := -1;
  433.     END;
  434.     queue[j].pg := page; queue[j].sp := subpage;
  435.   END;
  436. END;
  437.  
  438. PROCEDURE kill_job{(nr: Integer)};
  439. { einen Job löschen, <thisjob> nachführen, Bildschirm aber *nicht* }
  440. { aktualisieren }
  441. VAR j: Integer;
  442. BEGIN
  443.   IF nr>=0 THEN BEGIN  { aktiver Job }
  444.     activejobs[nr].pg := 0;
  445.     sperren(nr);
  446.   END ELSE IF (-nr<=queued) THEN BEGIN  { wartender Job }
  447.     FOR j := -nr TO queued-1 DO
  448.       queue[(firstinq+j-2) MOD qlen + 1] :=
  449.         queue[(firstinq+j-1) MOD qlen + 1];
  450.     Dec(queued);
  451.     IF fifo AND (thisjob<=nr) THEN Inc(thisjob);  { normal: thisjob=nr }
  452.     IF -thisjob>queued THEN Inc(thisjob);
  453.   END;
  454. END;
  455.  
  456. PROCEDURE cancel_job{(page: Integer)};
  457. { Als Erleichterung gegenüber kill_job() wird nicht die Position in der }
  458. { Warteschlange sondern der 'Name' des Jobs angegeben. }
  459. VAR j: Integer;
  460. BEGIN
  461.   FOR j := 0 TO maxactive-1 DO
  462.     IF activejobs[j].pg=page THEN kill_job(j);
  463.   FOR j := -queued TO -1 DO
  464.     IF queue[(-j+firstinq-2) MOD qlen + 1].pg=page THEN kill_job(j);
  465. END;
  466.  
  467. PROCEDURE hurricane;
  468. { Die Seiten aus der Seitensuche zurück in die Warteschlange fegen. }
  469. VAR j: Integer;
  470. BEGIN
  471.   FOR j := 0 TO maxactive-1 DO
  472.     requeue(j,False);
  473. END;
  474.  
  475. FUNCTION do_retry{: Integer};
  476. { Nicht gefundene Seiten aus der Seitenliste entfernen und neu anfordern. }
  477. { Rückgabewert ist die Anzahl betroffener Seiten. }
  478. VAR refresh: Boolean;
  479.     pg1, pg2: p_onepage;
  480.     hits: Integer;
  481.     s: String[20];
  482. BEGIN
  483.   hits := 0; refresh := False;
  484.   pg1 := root;
  485.   WHILE pg1<>Nil DO BEGIN
  486.     pg2 := pg1^.next;
  487.     IF (pg1^.cbits AND PF_LOCAL<>0) AND (pg1^.pg<$900) THEN BEGIN
  488.       Inc(hits);
  489.       IF pg1=visblpage THEN refresh := True;
  490.       s := hexstr(pg1^.pg,3); s := s + '/'+hexstr(pg1^.sp,1)
  491.       add_job(s, False);
  492.       del_from_list(pg1); update_list(pg2,-1);
  493.     END;
  494.     pg1 := pg2;
  495.   END;
  496.   redraw_queue(-1); IF refresh THEN writepage(thispage, True);
  497.   do_retry := hits;
  498. END;
  499.  
  500. PROCEDURE page_grabber{(mode: Byte)};
  501. { Rechenzeitintensive Variante der Seitensuche: alle Seiten einlesen, wie }
  502. { sie kommen. Mode=0: alle Seiten, mode=1: keine Pseudoseiten, mode=2: nur }
  503. { Seiten, die gerade in der Warteschlange stehen }
  504. { Prinzip des Algorithmus: }
  505. { Kreis 3  Kreis 2  Kreis 1  Kreis 0   (nach aufsteigender Priorität)  }
  506. {   *        x        x        x     |                                 }
  507. { =====      *                       |  === Kopfzeile     * anfordern  }
  508. { -----                              |  --- Folgezeile    x sperren    }
  509. { -----                              |  ^^^ Seite komplett             }
  510. { ^^^^^    =====      *              |                                 }
  511. {          -----                     | Gesucht wird i. a. nach Seite   }
  512. {          -----                     | "???", bei magazinparalleler    }
  513. {          ^^^^^    =====      *     | Übertragung dagegen nach "X??", }
  514. {                   -----            | wobei X=1..8 für alle 4 Kreise  }
  515. {                   -----            | gleich sein muß. }
  516. {                   ^^^^^    =====   | }
  517. { Jetzt sind die Seiten in 3, 2 und 1 stabil und komplett und können }
  518. { ausgelesen werden. }
  519. { Eine ganz naheliegende Idee wäre es, 3 und 2 bereits auszulesen, noch }
  520. { während man in 1 bzw. 0 auf Kopfzeilen wartet. }
  521. { Andererseits ist es wichtig, bereits die erste Seite, die nach der }
  522. { Anforderung eintrifft, im jeweiligen Kreis einzufrieren. Für alle }
  523. { danach eintreffenden Seiteninhalte wird der Speicher nämlich nicht mehr }
  524. { extra gelöscht, so daß unvollständig definierte Seiten (Schlagzeilen }
  525. { z. B.) mit ihren Vorgängern verschmelzen, was nicht so toll aussieht. }
  526. { Diese zeitoptimale Methode ist darum nur bei magazinparalleler }
  527. { Übertragung bedenkenlos möglich. Dort treffen aufeinanderfolgende }
  528. { Seiten eines Magazins nur ca. alle 0.8 sec ein, und so schnell geht das }
  529. { Einlesen über den I²C-Bus noch allemal (ca. 0.4 sec/Seite). }
  530. VAR i, j, mag, anz, neu, lastq: Integer;
  531.     seite, dummy: p_onepage;
  532.     timeout, parmode, redraw: Boolean;
  533.     datei: Text;
  534.     sender, zeile, name: str80;
  535. PROCEDURE waitforpg(unit: Integer);
  536. { max. 5 Sekunden auf das Eintreffen einer Seite warten }
  537. VAR t0,t: zeiteintrag;
  538. BEGIN
  539.   uhrzeit(t0);
  540.   REPEAT
  541.     uhrzeit(t); timeout := diff_time(t0,t)>250;
  542.   UNTIL seite_da(unit) OR timeout;
  543. END;
  544. PROCEDURE einlesen(unit: Integer);
  545. { neue Seite einlesen (sofern nicht schon vorhanden) und einreihen }
  546. VAR style: Integer;
  547. BEGIN
  548.   style := 0;
  549.   getpage(unit,dummy,False); Inc(anz);
  550.   IF wanted[dummy^.pg] THEN BEGIN
  551.     seite := hunt_in_list(dummy^.pg,dummy^.sp,True);
  552.     IF seite=Nil THEN BEGIN
  553.       New(seite); Inc(neu); style := 1;
  554.       getpage(unit,seite,True); add_sp_number(seite); 
  555.       ins_to_list(seite); update_list(seite, 1);
  556.       IF (mode=2) AND (dummy^.sp IN [0,1]) THEN cancel_job(dummy^.pg);
  557.     END;    
  558.   END;
  559.   IF unit=3 THEN short_msg('Stichprobe:',0);
  560.   add_msg(' '+hexstr(dummy^.pg,3), style);
  561. END;
  562. BEGIN
  563.   hurricane; redraw_queue(-1);  { Seitensuche freimachen }
  564.   { Suchfilter festlegen: }
  565.   FOR i := $100 TO $8FF DO wanted[i] := (mode=0);
  566.   IF mode=1 THEN 
  567.     FOR i := 100 TO 899 DO wanted[make_bcd(i)] := True;
  568.   IF mode=2 THEN BEGIN
  569.     anz := 0;
  570.     FOR i := 0 TO queued-1 DO BEGIN
  571.       j := firstinq + i; IF j>qlen THEN j := 1;
  572.       j := queue[j].pg;
  573.       IF (j IN [$100..$8FF]) AND NOT wanted[j] THEN BEGIN
  574.         wanted[j] := True; Inc(anz);
  575.       END;
  576.     END;
  577.     short_msg(IntStr(anz)+' gesuchte Seitennummern',0);
  578.   END;
  579.   New(dummy);
  580.   anz := 0; neu := 0;
  581.   REPEAT
  582.     redraw := (root=Nil); lastq := queued;
  583.     FOR i := 0 TO 2 DO sperren(i);
  584.     anfordern(3,$100,0,%000);
  585.     waitforpg(3); getpage(3,dummy,False);
  586.     parmode := (dummy^.cbits AND PF_SERMAG)=0;
  587.     IF parmode THEN BEGIN  { magazinparallele Sendefolge ;-\ }
  588.       FOR i := 3 DOWNTO -1 DO IF NOT timeout THEN BEGIN
  589.         { indirektes Sperren von (i+1): }
  590.         IF i>-1 THEN anfordern(i,dummy^.pg,0,%100)
  591.         { Die Seite in (i+2) ist bereits komplett und stabil: }
  592.         IF i<2 THEN einlesen(i+2);
  593.         { jetzt auf die zuletzt angeforderte Seite warten: }
  594.         IF i>-1 THEN waitforpg(i);
  595.       END
  596.     END ELSE BEGIN  { normale, magazinserielle Sendefolge }
  597.       FOR i := 2 DOWNTO 0 DO IF NOT timeout THEN BEGIN
  598.         { (i+1) sperren und auf die nächste Seite warten: }
  599.         anfordern(i,$100,0,%000); waitforpg(i);
  600.       END;
  601.       { alle kompletten Seiten einlesen: }      
  602.       IF NOT timeout THEN
  603.         FOR i := 3 DOWNTO 1 DO einlesen(i);
  604.     END;
  605.     IF redraw AND NOT timeout THEN writepage(thispage, True);
  606.     IF queued<lastq THEN redraw_queue(-1);
  607.     event_scan(True);
  608.   UNTIL newevent OR timeout;
  609.   IF timeout THEN BEGIN
  610.     short_msg('keine neuen Seiten - Abbruch',0);
  611.   END;
  612.   Dispose(dummy);
  613.   FOR i := 0 TO 3 DO sperren(i);
  614. END;
  615.  
  616. PROCEDURE topgrab{(pg0: p_onepage)};
  617. { alle laut TOP-Text verfügbaren Seiten anfordern, allerdings nur bis zu }
  618. { der durch <toplevel> vorgegebenen Priorität }
  619. CONST interleave=10;
  620. VAR i,j,n,level: Integer;
  621.     pri: ARRAY[0..17] OF Char;
  622. BEGIN
  623.   pri := '-KABCDEFHGJI-----';
  624.   FOR level := 1 TO toplevel DO
  625.     FOR i := 0 TO interleave-1 DO
  626.       FOR j := 0 TO 799 DIV interleave DO BEGIN
  627.         n := 100 + j*interleave + i;
  628.         IF (n<900) THEN BEGIN
  629.           IF Ord(pri[topcode[pg0^.chars[n-60]]])-64=level THEN
  630.             add_job(IntStr(n),True);   { nach absteigender Priorität }
  631.         END;
  632.       END;
  633.   redraw_queue(-1);
  634. END;
  635.  
  636. PROCEDURE getconfig{(nr: Integer)};
  637. VAR datei: Text;
  638.     sender, zeile, name: str80;
  639.     save_fifo: Boolean;
  640.     t,block: Integer;
  641. BEGIN
  642.   gethead(name); name2dosname(name,sender);
  643.   name := configpath+sender;
  644.   Reset(datei,name);
  645.   IF IOResult<>0 THEN BEGIN
  646.     short_msg('keine Auswahl für "'+sender+'" vorhanden',2);
  647.     add_job('100',False);
  648.     redraw_queue(-1);
  649.     Exit;
  650.   END;
  651.   Buffer(datei,500);
  652.   short_msg('hole ',0); IF nr>1 THEN add_msg(IntStr(nr)+'. ',0);
  653.   add_msg('Seitenauswahl für "'+sender+'"',0);
  654.   block := 1;
  655.   save_fifo := fifo; fifo := True;
  656.   WHILE NOT EoF(datei) DO BEGIN
  657.     ReadLn(datei,zeile);
  658.     t := Length(zeile); WHILE t>0 DO BEGIN
  659.       IF zeile[t]=' ' THEN zeile[t] := #0; Dec(t);
  660.     END;
  661.     IF zeile='' THEN 
  662.       Inc(block)   { Leerzeile trennt Blöcke }
  663.     ELSE IF block=nr THEN
  664.       add_job(zeile,True);
  665.   END;
  666.   Close(datei);
  667.   fifo := save_fifo;
  668.   redraw_queue(-1);
  669. END;
  670.  
  671. LIBRARY DosBase:  { Include-Files nein danke }
  672. -222 : FUNCTION  Execute(D1: Str; D2,D3: Long): Boolean;
  673. END;
  674.  
  675. FUNCTION ed_config{(hint: p_onepage): Boolean};
  676. { Seitenvorauswahl für den aktuellen Sender editieren }
  677. VAR fenster: Text;
  678.     s,datei: Str80;
  679.     i: Integer;
  680. BEGIN
  681.   s[25] := #0;
  682.   IF hint=Nil THEN
  683.     gethead(s)
  684.   ELSE FOR i := 1 TO 24 DO BEGIN
  685.     s[i] := Chr(hint^.chars[i+7]);
  686.     IF s[i]<' ' THEN s[i] := ' ';
  687.   END;
  688.   name2dosname(s,datei);
  689.   showscreen(0);
  690.   Reset(fenster,'CON:100/100/440/80/VT-Ausgabefenster');
  691.   s := editor + configpath + datei;
  692.   ed_config := Execute(s,0,FileHandle(fenster));
  693.   Close(fenster);
  694.   showscreen(2);
  695. END;
  696.  
  697. FUNCTION ed_stations{: Boolean};
  698. { Editoraufruf für die ".stations"-Liste }
  699. VAR fenster: Text;
  700.     s: Str80;
  701. BEGIN
  702.   showscreen(0);
  703.   Reset(fenster,'CON:100/100/440/80/VT-Ausgabefenster');
  704.   s := editor + configpath + '.stations';
  705.   ed_stations := Execute(s,0,FileHandle(fenster));
  706.   Close(fenster);
  707.   showscreen(2);
  708. END;
  709.  
  710. PROCEDURE dump_numbers;
  711. { Seitennummern ins Clipboard schreiben, Hilfe beim Ändern der Vorauswahlen }
  712. VAR anz,nextnr: Integer;
  713.     hilf: p_onepage;
  714.     ok: Boolean;
  715.     s: str80;
  716. BEGIN
  717.   IF root=Nil THEN Exit;
  718.   anz := 0; 
  719.   hilf := root;
  720.   WHILE hilf<>Nil DO BEGIN
  721.     IF hilf^.next=Nil THEN nextnr := -1 ELSE nextnr := hilf^.next^.pg;
  722.     IF (hilf^.pg<$900) AND (hilf^.pg<>nextnr) THEN Inc(anz);
  723.     hilf := hilf^.next;
  724.   END;
  725.   start_clip(4*anz);
  726.   hilf := root;
  727.   WHILE hilf<>Nil DO BEGIN
  728.     IF hilf^.next=Nil THEN nextnr := -1 ELSE nextnr := hilf^.next^.pg;
  729.     IF (hilf^.pg<$900) AND (hilf^.pg<>nextnr) THEN BEGIN
  730.       s := hexstr(hilf^.pg,3)+#10; clip_it(s,4);
  731.     END;
  732.     hilf := hilf^.next;
  733.   END;
  734.   end_clip;
  735. END;
  736.  
  737. PROCEDURE dump_title{(seite: p_onepage)};
  738. { Sendernamen ins Clipboard schreiben }
  739. VAR s: str80;
  740.     i: Integer;
  741. BEGIN
  742.   start_clip(24);
  743.   IF seite=Nil THEN 
  744.     gethead(s)
  745.   ELSE FOR i := 1 TO 24 DO BEGIN
  746.     s[i] := Chr(seite^.chars[i+7]);
  747.     IF s[i]<' ' THEN s[i] := ' ';
  748.   END;
  749.   s[25] := #0;
  750.   clip_it(s,24);
  751.   end_clip;
  752. END;
  753.  
  754. BEGIN  { Initialisierungen }
  755.   editor := 'c:Ed '; { Editor für configs }
  756.   toplevel := 4;  { nur Programm- und Blockseiten }
  757.   maxwait := 80;
  758.   burst := 0;
  759.   shuffle := 20;
  760. END.
  761.