home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / HardwareProjects / VideoText.lha / VideoText4.2 / source / jobs.p < prev    next >
Encoding:
Text File  |  1995-06-29  |  20.5 KB  |  598 lines

  1. UNIT jobs; {$project vt }
  2. { Job-Verwaltung zum Programm VideoText }
  3.  
  4. INTERFACE; FROM vt USES datei;
  5.  
  6. VAR editor,configpath: Str80;
  7.     toplevel: Integer;
  8.     active: Byte; { aktive Jobs in der Seitensuche }
  9.     maxwait, burst,shuffle: Integer;
  10.  
  11. PROCEDURE sleep;
  12. PROCEDURE wakeup;
  13. PROCEDURE handle_queue;
  14. PROCEDURE handle_jobs;
  15. PROCEDURE attempt_input(job: Integer);
  16. PROCEDURE add_job(entry: Str80; blind: Boolean);
  17. PROCEDURE topselect(pg1,pg2,pg3: p_onepage);
  18. PROCEDURE topgrab(pg1,pg2: p_onepage);
  19. PROCEDURE getconfig(nr: Integer);
  20. PROCEDURE edconfig(nr: Integer);
  21. PROCEDURE dump_numbers;
  22.  
  23. { ---------------------------------------------------------------------- }
  24.  
  25. IMPLEMENTATION;
  26.  
  27. {$ opt q,s+,i+} { keine Laufzeitprüfungen außer Stack und Feldindizes }
  28.  
  29. CONST SERMAG = $0800; { C11 }
  30.       RENEW  = $0100; { C8 }
  31.       STITLE = $0040; { C6 }
  32.       HEADLN = $0020; { C5 }
  33.  
  34. VAR bedtime: zeiteintrag;
  35.  
  36. PROCEDURE uhrzeit(VAR zeit: zeiteintrag);
  37. BEGIN
  38.   telltime(zeit.tage,zeit.min,zeit.tics);
  39. END;
  40.  
  41. PROCEDURE add_time(delta: zeiteintrag; VAR zeit: zeiteintrag);
  42. BEGIN
  43.   IF zeit.tics + delta.tics>=3000 THEN Inc(zeit.min);
  44.   zeit.tics := (zeit.tics + delta.tics) MOD 3000;
  45.   IF zeit.min + delta.min>=1440 THEN Inc(zeit.tage);
  46.   zeit.min := (zeit.min + delta.min) MOD 1440;
  47.   zeit.tage := zeit.tage + delta.tage;
  48. END;
  49.  
  50. PROCEDURE sub_time(delta: zeiteintrag; VAR zeit: zeiteintrag);
  51. BEGIN
  52.   IF zeit.tics - delta.tics<0 THEN Dec(zeit.min);
  53.   zeit.tics := (zeit.tics - delta.tics + 3000) MOD 3000;
  54.   IF zeit.min - delta.min<0 THEN Dec(zeit.tage);
  55.   zeit.min := (zeit.min - delta.min + 1440) MOD 1440;
  56.   zeit.tage := zeit.tage - delta.tage;
  57. END;
  58.  
  59. FUNCTION diff_time(alt, neu: zeiteintrag): Long;
  60. { liefert die Differenz zwischen zwei Zeitpunkten in Ticks (1/50-Sekunden) }
  61. BEGIN
  62.   diff_time := neu.tics - alt.tics + 3000 * ( (neu.min - alt.min)
  63.                + 1440 * (neu.tage - alt.tage) );
  64. END;
  65.  
  66. PROCEDURE sleep;
  67. { wird vor Unterbrechung der Hauptschleife (z. B. durch FileRequester) }
  68. { aufgerufen }
  69. BEGIN
  70.   uhrzeit(bedtime);
  71. END;
  72.  
  73. PROCEDURE wakeup;
  74. { Verhindert in Zusammenarbeit mit sleep, daß Zeiten, während derer der }
  75. { VT-Decoder gar nicht abgefragt wird, zum Löschen von Jobs wegen }
  76. { Zeitüberschreitung führen. }
  77. VAR delta: zeiteintrag;
  78.     j: Integer;
  79. BEGIN
  80.   uhrzeit(delta);
  81.   sub_time(bedtime,delta);
  82.   FOR j := 0 TO maxactive-1 DO
  83.     add_time(delta,activejobs[j].lastaction);
  84. END;
  85.  
  86. PROCEDURE count_them;
  87. { durchzählen, wer in der Seitensuche alles bedient werden will: }
  88. VAR j: Integer;
  89. BEGIN
  90.   active := 0;
  91.   FOR j := 0 TO maxactive-1 DO
  92.     IF (activejobs[j].pg>0) THEN Inc(active);
  93. END;
  94.  
  95. PROCEDURE handle_queue;
  96. { Verwaltet das Aufrücken wartender Jobs. }
  97. { Jobs mit unbestimmter Unterseitennummer, also mit /0, /*, /., /! können }
  98. { aktive Jobs mit gleicher Seitennummer aus der Seitensuche verdrängen }
  99. VAR i,j,killer: Integer;
  100. BEGIN
  101.   REPEAT
  102.     j := -1;
  103.     IF queued>0 THEN BEGIN
  104.       { Soll ein aktiver Job verdrängt werden? }
  105.       IF queue[firstinq].sp<1 THEN
  106.         FOR i := 0 TO maxactive-1 DO
  107.           IF activejobs[i].pg=queue[firstinq].pg THEN j := i;
  108.       { Oder ist ein Platz in der Seitensuche frei? }
  109.       IF j<0 THEN
  110.         FOR i := maxactive-1 DOWNTO 0 DO
  111.           IF activejobs[i].pg=0 THEN j := i;
  112.     END;
  113.     IF j>=0 THEN BEGIN
  114.       { Empfangseinheit <j> mit wartendem Job belegen }
  115.       { Ein wartender Job besteht nur aus Seiten- und Unterseitennummer, }
  116.       { jetzt kommen eine Menge Informationen dazu. }
  117.       WITH activejobs[j] DO BEGIN
  118.         pg := queue[firstinq].pg; sp := queue[firstinq].sp;
  119.         sp_count := 0; sp_max := 0;
  120.         holen := False; erledigt := False;
  121.         FOR i := 0 TO maxsubpage DO sp_check[i] := False;
  122.         uhrzeit(lastaction);
  123.         anfordern(j,pg,sp,%111);
  124.       END;
  125.       IF i2c_status<>0 THEN   { Oh Mann! Dummer I²C-Bus! }
  126.         activejobs[j].pg := 0   { Kommando zurück }
  127.       ELSE BEGIN
  128.         { Warteschlange aufrücken: }
  129.         Dec(queued); Inc(firstinq); IF firstinq>qlen THEN firstinq := 1;
  130.         { Auswahlzeiger des Benutzers dem Aufrücken entsprechend nachführen: }
  131.         IF thisjob=-1 THEN thisjob := j
  132.           ELSE IF thisjob<0 THEN Inc(thisjob);
  133.         IF thisjob>=0 THEN BEGIN
  134.           aktspeicher := thisjob; display_select(aktspeicher); END;
  135.         redraw_queue(-1);
  136.       END;
  137.     END;
  138.   UNTIL j<0; { kein Platz mehr gefunden }
  139.   IF queued=0 THEN fifo := True; { Warteschlange normalisieren }
  140.   count_them;
  141. END;
  142.  
  143. PROCEDURE rausschmeisser;
  144. { Prüfen, ob ein Job wegen Zeitüberschreitung gestrichen werden kann. }
  145. { Wenn der Job allerdings so lange wartet, weil er sich auf eine einzelne }
  146. { Unterseite bezieht, ist ihm verziehen und er wird lediglich ans Ende der }
  147. { Warteschlange gesetzt. Und für festgehaltene Seitennummern findet eine }
  148. { Prüfung auf Zeitüberschreitung gar nicht erst statt. }
  149. VAR i, j: Integer;
  150.     jetzt: zeiteintrag;
  151. BEGIN
  152.   uhrzeit(jetzt);
  153.   FOR j := 0 TO maxactive-1 DO WITH activejobs[j] DO
  154.     IF (pg<>0) AND (diff_time(lastaction,jetzt) > 50*maxwait)
  155.     AND (sp>-2) THEN  { keine "festgehaltenen" Seiten! }
  156.       IF sp IN [0,-1] THEN BEGIN
  157.         { einfache Seitennummer streichen }
  158.         pg := 0; sperren(j); redraw_queue(j);
  159.       END ELSE IF (queued>0) AND (queued<qlen) THEN BEGIN
  160.         { Unterseitenanforderung nur hintenanstellen }
  161.         i := firstinq+queued; IF i>qlen THEN i := 1;
  162.         Inc(queued);
  163.         queue[i].pg := pg; queue[i].sp := sp;
  164.         pg := 0; sperren(j); redraw_queue(-1);
  165.       END;
  166.   count_them;
  167. END;
  168.  
  169. PROCEDURE handle_jobs;
  170. { Überprüft, ob in einem der Empfangskreise eine Seite eingetroffen ist, und }
  171. { wenn ja, ob sie aufgrund ihrer Unterseitennummer überhaupt eingelesen }
  172. { werden muß. Es wird auch entschieden, ob der Job durch die eingetroffene }
  173. { Seite erledigt ist. Kriterium für 'erledigt': }
  174. { Ein Job mit sp<>0 ist erledigt, sobald die eine angeforderte Unterseite }
  175. { da ist. Ein Job mit sp=0 ist erst dann erledigt, wenn alle seine }
  176. { Unterseiten eingelesen wurden. Ein festgehaltener Job (sp=-2) ist niemals }
  177. { erledigt und muß anderweitig entfernt werden. }
  178. { Einlesen der Seite geschieht an anderer Stelle, s. u. }
  179. VAR j: Integer;
  180.     dummy: p_onepage;
  181.     sp_decval: Integer;
  182. BEGIN
  183.   rausschmeisser;
  184.   { Schauen, ob irgendwo das Eintreffen einer Kopfzeile gemeldet wurde: }
  185.   FOR j := 0 TO maxactive-1 DO WITH activejobs[j] DO
  186.     IF (pg>0) AND NOT holen THEN IF seite_da(j) THEN BEGIN
  187.       New(dummy);
  188.       uhrzeit(lastaction);
  189.       getpage(j,dummy,false); { *nur* Status und Seitennummer holen }
  190.       sp_decval := bcd(dummy^.sp);
  191.       { *** Schauen, ob die Seite eingelesen werden muß. Gründe, weswegen }
  192.       {   man eine Seite evtl. nicht haben will: }
  193.       { 1.: Unterseite wurde bereits eingelesen. }
  194.       {   (Bei zu großen Unterseitennummern kann das nur über ein etwas }
  195.       {   armseliges Hilfskriterium festgestellt werden.) }
  196.       IF (sp_decval<=maxsubpage) THEN holen := NOT sp_check[sp_decval]
  197.         ELSE holen := (dummy^.sp>sp_max);
  198.       {   für festgehaltene Seiten ist "bereits eingelesen" überhaupt kein }
  199.       {   Hinderungsgrund: }
  200.       IF sp=-2 THEN holen := True;
  201.       { 2.: Nur eine Unterseite war angefordert, und zwar nicht diese. }
  202.       {   Das dürfte allerdings kaum vorkommen, da der CCT ausdrücklich auf }
  203.       {   die eine Unterseite programmiert wurde. }
  204.       IF (sp>0) THEN
  205.         holen := (dummy^.sp=sp)
  206.       { *** Unterseitenverwaltung aktualisieren: }
  207.       IF holen THEN BEGIN
  208.         Inc(sp_count);
  209.         IF (sp_decval<=maxsubpage) THEN  sp_check[sp_decval] := True;
  210.         IF dummy^.sp>sp_max  THEN sp_max := dummy^.sp;
  211.         akt_sp := dummy^.sp;
  212.         redraw_queue(j);
  213.       END;
  214.       { *** Prüfen, ob der Job durch die eingetroffene Seite erledigt ist. }
  215.       {   Das geht z. B. durch Unterseite 0 (= einzige Unterseite), auf }
  216.       {   keinen Fall aber durch eine Unterseite mit der bislang höchsten }
  217.       {   Nummer. }
  218.       IF sp_check[0] THEN
  219.         erledigt := sp_count>bcd(sp_max)
  220.       ELSE IF dummy^.sp<sp_max THEN
  221.         erledigt := sp_count=bcd(sp_max);
  222.       { Auch möglich: die einzig geforderte Unterseite ist da. }
  223.       IF (sp<>0) AND holen THEN
  224.         erledigt := True;
  225.       { *** Schauen, ob magazinserielle oder -gemischte Übertragung vorliegt }
  226.       {   und danach die Wartezeit festlegen: }
  227.       IF (dummy^.cbits AND SERMAG)=0 THEN
  228.         wartezeit := shuffle ELSE wartezeit := burst;
  229.       IF NOT holen THEN
  230.         anfordern(j,pg,sp,%111);   { Suche geht weiter, PBLF setzen }
  231.       Dispose(dummy);
  232.     END;
  233. END;
  234.  
  235. PROCEDURE attempt_input{(job: Integer)};
  236. { Das Einlesen geschieht in einem zweiten Schritt, da nach Eintreffen der }
  237. { Kopfzeile erst eine Weile gewartet werden muß. }
  238. { Evtl. wird die Seite auch gleich ausgegeben: auf dem Bildschirm, falls }
  239. { <thisjob> auf den zugehörigen Job zeigt oder wenn eine festgehaltene }
  240. { Seite aktualisiert wurde; in die Ausgabedatei, falls es eine zu }
  241. { protokollierende Seite war. }
  242. { Jobs, die nach diesem Einlesen erledigt sind, wurden bereits entsprechend }
  243. { gekennzeichnet und werden aus der Liste gestrichen. }
  244. VAR dummy,seite: p_onepage;
  245.     jetzt: zeiteintrag;
  246.     exciting: Boolean;
  247. BEGIN
  248.   { Prüfen, ob die Wartezeit für eine einzulesende Seite um ist: }
  249.   WITH activejobs[job] DO
  250.     IF (pg>0) AND holen THEN BEGIN
  251.       uhrzeit(jetzt);
  252.       IF diff_time(lastaction,jetzt) >= wartezeit THEN BEGIN
  253.         { Seite einlesen: }
  254.         busy_pointer;
  255.         { Ist bereits eine alte Version dieser Seite in der Liste, die dann }
  256.         { lediglich überschrieben werden müßte? }
  257.         seite := hunt_in_list(pg,akt_sp,True);
  258.         IF seite=Nil THEN BEGIN
  259.           New(seite);
  260.           getpage(job,seite,True);
  261.           normal_pointer;
  262.           IF i2c_status<>0 THEN BEGIN Dispose(seite); Exit; END;
  263.           ins_to_list(seite);
  264.           update_list(seite,1);
  265.         END ELSE BEGIN
  266.           getpage(job,seite,True);
  267.           normal_pointer;
  268.           IF i2c_status<>0 THEN Exit;
  269.         END;
  270.         { Hat sich eine überwachte Seite geändert bzw. ist zum ersten Mal}
  271.         { eingetroffen? }
  272.         exciting := (sp<-1) AND ((sp_count=1) OR (seite^.cbits AND RENEW<>0))
  273.             AND (seite^.cbits AND STITLE=0); { Untertitel ausgenommen! }
  274.         { bildschirmüberwachte Seite anzeigen: }
  275.         IF (seite=thispage) OR (exciting AND (sp=-2)) THEN BEGIN
  276.           mainline; IF seite<>thispage THEN
  277.             Write('neuer Inhalt S. ',hexstr(pg,3),'!');
  278.           writepage(seite,True);
  279.           IF seite<>thispage THEN BEGIN
  280.             mainline; Write('bitte Leertaste dr}cken'); END;
  281.         END;
  282.         { dateiüberwachte Seite abspeichern (diesmal auch Untertitel): }
  283.         IF sp=-3 THEN
  284.           IF exciting OR (seite^.cbits AND STITLE<>0) THEN BEGIN
  285.             sleep; IF save_action(seite,1)=0 THEN BEGIN
  286.               { nach einmal genehmigtem Überschreiben auf Anhängen umschalten: }
  287.               overwrite := False; fileinfo;
  288.             END ELSE
  289.               sp_count := 0; { nach fehlgeschlagenem Speichern }
  290.               { sofort beim nächsten Mal wieder versuchen lassen }
  291.             wakeup;
  292.           END ELSE
  293.             mainline;
  294.         holen := False;  { Wichtig !!! }
  295.         anfordern(job,pg,sp,%111);   { um PBLF wieder zu setzen }
  296.       END;
  297.     END;
  298.   { Erledigten Job löschen, außer es ist ein festgehaltener Job: }
  299.   WITH activejobs[job] DO
  300.     IF (pg>0) AND erledigt AND NOT holen THEN
  301.       IF (sp<-1) THEN BEGIN   { nicht löschen }
  302.         { nur die Zähler zurücksetzen, außer sp_count }
  303.         sp_check[0] := False; sp_max := 0; erledigt := False;
  304.         redraw_queue(job);
  305.       END ELSE BEGIN  { löschen }
  306.         pg := 0; sperren(job); redraw_queue(job);
  307.       END;
  308.   count_them;
  309. END;
  310.  
  311. PROCEDURE add_job{(entry: Str80; blind: Boolean)};
  312. { Eine Eingabe, die eine Seitennummer darstellt (oder auch nicht), in die }
  313. { Warteschlange einzureihen versuchen. }
  314. { Bei blind=False wird noch überprüft, ob sich vielleicht bereits ein }
  315. { identischer Job in der Seitensuche befindet. }
  316. VAR i,j,page,subpage: Integer;
  317.     s: str80;
  318.     ok: Boolean;
  319. BEGIN
  320.   j := Pos('/',entry);
  321.   IF j > 0 THEN BEGIN
  322.     page := hexval(Copy(entry,1,j-1));
  323.     subpage := hexval(Copy(entry,j+1,Length(entry)-j));
  324.     IF entry[j+1]='*' THEN subpage := -1;
  325.     IF entry[j+1]='.' THEN subpage := -2;
  326.     IF entry[j+1]='!' THEN subpage := -3;
  327.   END ELSE BEGIN
  328.     page := hexval(entry);
  329.     subpage := 0;
  330.   END;
  331.   ok := (page>=$100) AND (page<$900);
  332.   { evtl. weitere Einschränkung: mit bereits vorhandenen Jobs vergleichen }
  333.   { und keinen Job zulassen, der ein Verdrängen bewirken würde }
  334.   IF NOT blind THEN BEGIN
  335.     FOR j := 0 TO maxactive-1 DO
  336.       IF (activejobs[j].pg=page) AND (subpage<1) THEN ok := False;
  337.     FOR j := 1 TO queued DO BEGIN
  338.       i := (firstinq + j - 2) MOD qlen + 1;
  339.       IF (queue[i].pg=page) AND (subpage<1) THEN ok := False;
  340.     END;
  341.   END;
  342.   IF ok AND (queued<qlen) THEN BEGIN
  343.     IF fifo THEN BEGIN
  344.       j := firstinq+queued; IF j>qlen THEN j := 1;
  345.     END ELSE BEGIN
  346.       Dec(firstinq); IF firstinq=0 THEN firstinq := qlen; j := firstinq;
  347.     END;
  348.     Inc(queued);
  349.     queue[j].pg := page; queue[j].sp := subpage;
  350.   END;
  351. END;
  352.  
  353. PROCEDURE topselect{(pg1,pg2,pg3: p_onepage)};
  354. { benutzt die TOPtext-Seiten 1F2 [1F3 [1F4]] für Seitenauswahl }
  355. { ergibt eine Tabelle von [2/4/6] * 23 Schlagworten und Seitennummern }
  356. VAR i,j,k,npg,anz,mag: Integer;
  357.     nums: ARRAY [1..23,1..6] OF Integer;
  358.     names: ARRAY [1..23,1..6] OF String[13];
  359.     select: ARRAY [1..23,1..6] OF Boolean;
  360.     pg: ARRAY[1..3] OF p_onepage;
  361.     color: ARRAY[0..8] OF String[10]; { Farbkombinationen für die 8 Magazine }
  362.     s: str80;
  363.     l: Long;
  364.     ch: Char;
  365. PROCEDURE entry(i,j: Integer; marked: Boolean);
  366. BEGIN
  367.   IF npg=3 THEN GotoXY(13*(j-1)+1,i) ELSE GotoXY(18*(j-1)+5,i);
  368.   Write(#155'0m');
  369.   IF marked THEN Write(#155'31;42m');
  370.   IF select[i,j] THEN Write('*') ELSE Write(' ');
  371.   Write(#155'0m',color[nums[i,j] DIV 100]);
  372.   IF marked AND (npg=3) THEN
  373.     Write(Copy(names[i,j],1,8)) ELSE Write(names[i,j]);
  374.   IF (marked OR (npg<3)) AND (nums[i,j]>0) THEN
  375.     Write(nums[i,j]:4)
  376. END;
  377. PROCEDURE toggle_by_click(x,y: Integer);
  378. VAR jj: Integer;
  379. BEGIN
  380.   IF npg=3 THEN BEGIN
  381.     jj := (x-1) DIV 13 + 1;
  382.   END ELSE BEGIN
  383.     jj := (x-5) DIV 18 + 1; IF (x-5) MOD 18=17 THEN jj := 0;
  384.   END;
  385.   IF (y IN [1..23]) AND (jj IN [1..2*npg]) THEN BEGIN
  386.     entry(i,j,False);
  387.     i := y; j := jj;
  388.     IF nums[i,j]>0 THEN select[i,j] := NOT select[i,j];
  389.     entry(i,j,True);
  390.   END;
  391. END;
  392. BEGIN
  393.   pg[1] := pg1; pg[2] := pg2; pg[3] := pg3;
  394.   npg := 0; FOR i := 1 TO 3 DO IF pg[i]<>Nil THEN Inc(npg);
  395.   color[0] := #155'0m'; { getarnt }
  396.   color[1] := #155'3'+colperms[6]+';4'+colperms[0]+'m'; { Cyan auf Schwarz }
  397.   color[2] := #155'3'+colperms[6]+';4'+colperms[4]+'m'; { Cyan auf Blau }
  398.   color[3] := #155'3'+colperms[7]+';4'+colperms[5]+'m'; { Weiß auf Purpur }
  399.   color[4] := #155'3'+colperms[7]+';4'+colperms[1]+'m'; { Weiß auf Rot }
  400.   color[5] := #155'3'+colperms[3]+';4'+colperms[0]+'m'; { Gelb auf Schwarz }
  401.   color[6] := #155'3'+colperms[3]+';4'+colperms[4]+'m'; { Gelb auf Blau }
  402.   color[7] := #155'3'+colperms[3]+';4'+colperms[5]+'m'; { Gelb auf Purpur }
  403.   color[8] := #155'3'+colperms[3]+';4'+colperms[1]+'m'; { Gelb auf Rot }
  404.   ClrScr; GotoXY(1,25); Write(#155'0m');
  405.   WriteLn(#155'2mTOP-Text Themen}bersicht:'#155'0m <Crsr>, <Sp>: markieren, <BS>/<Del>: Korrektur');
  406.   Write('<Esc>: Abbruch, <Return>: Auswahl }bernehmen und Ende');
  407.   FOR i := 1 TO 23 DO
  408.     FOR j := 1 TO 2*npg DO BEGIN
  409.       gettopnum(pg[(j+1) DIV 2],20*(1-j MOD 2),i,nums[i,j],k);
  410.       IF (nums[i,j]<0) OR (k<0) OR (nums[i,j]>$899) THEN
  411.         nums[i,j] := 0; { ungültige Codierung! }
  412.       nums[i,j] := bcd(nums[i,j]);
  413.       names[i,j][13] := #0;
  414.       FOR k := 1 TO 12 DO BEGIN
  415.         names[i,j][k] := Chr(pg[(j+1) DIV 2]^.chars[40*i+20*(1-j MOD 2)+7+k]);
  416.         IF names[i,j][k]<' ' THEN names[i,j][k] := ' ';
  417.       END;
  418.       select[i,j] := False;
  419.       entry(i,j,False);
  420.     END;
  421.   i := 1; j := 1; entry(i,j,True);
  422.   REPEAT
  423.     l := Wait(-1);
  424.     ch := readkey; s := '';
  425.     CASE ch OF
  426.       ' ': BEGIN
  427.           IF nums[i,j]>0 THEN select[i,j] := True;
  428.           entry(i,j,False);
  429.           IF i<23 THEN Inc(i) ELSE
  430.             IF j<2*npg THEN BEGIN Inc(j); i := 1; END;
  431.           entry(i,j,True);
  432.         END;
  433.       #8: BEGIN
  434.           entry(i,j,False);
  435.           IF i>1 THEN Dec(i) ELSE
  436.             IF j>1 THEN BEGIN Dec(j); i := 23; END;
  437.           select[i,j] := False; entry(i,j,True);
  438.         END;
  439.       #127: BEGIN
  440.           select[i,j] := False; entry(i,j,True);
  441.         END;
  442.       #155: REPEAT ch := readkey; s := s+ch; UNTIL ch>='@';
  443.       OTHERWISE;
  444.     END;
  445.     IF s[1] IN ['A'..'D','S','T'] THEN BEGIN
  446.       entry(i,j,False);
  447.       CASE s[1] OF
  448.         'A': IF i>1 THEN Dec(i);
  449.         'B': IF i<23 THEN Inc(i);
  450.         'C': IF j<2*npg THEN Inc(j);
  451.         'D': IF j>1 THEN Dec(j);
  452.         'S': i := 23;
  453.         'T': i := 1;
  454.         OTHERWISE;
  455.       END;
  456.       entry(i,j,True);
  457.     END;
  458.     intui_events;
  459.     IF mouseclicked THEN BEGIN
  460.       toggle_by_click(clickedx,clickedy);
  461.       mouseclicked := False;
  462.     END;
  463.   UNTIL (ch IN [#13,#27]) OR stop;
  464.   IF ch=#13 THEN
  465.     FOR i := 1 TO 23 DO
  466.       FOR j := 1 TO 2*npg DO
  467.         IF select[i,j] THEN add_job(IntStr(nums[i,j]),True);
  468. END;
  469.  
  470. PROCEDURE topgrab{(pg1,pg2: p_onepage)};
  471. { alle laut TOP-Text verfügbaren Seiten anfordern, allerdings nur bis zu }
  472. { der durch <toplevel> vorgegebenen Priorität }
  473. CONST interleave=10;
  474. VAR i,j,n,level: Integer;
  475.     pri: ARRAY[0..17] OF Char;
  476. BEGIN
  477.   pri := '-KABCDEFHGJI-----';
  478.   fifo := True;
  479.   FOR level := 1 TO toplevel DO
  480.     FOR i := 0 TO interleave-1 DO
  481.       FOR j := 0 TO 799 DIV interleave DO BEGIN
  482.         n := 100 + j*interleave + i;
  483.         IF (n<900) THEN BEGIN
  484.           IF Ord(pri[topcode[pg1^.chars[n-60]]])-64=level THEN
  485.             add_job(IntStr(n),True);   { nach absteigender Priorität }
  486.         END;
  487.       END;
  488.   redraw_queue(-1);
  489. END;
  490.  
  491. PROCEDURE getconfig{(nr: Integer)};
  492. VAR datei: text;
  493.     sender, zeile, name: Str80;
  494.     is_header, found, anything: boolean;
  495.     t: integer;
  496. BEGIN
  497.   IF activejobs[0].pg=0 THEN BEGIN
  498.     anfordern(0,100,0,%000);
  499.     t := 50;   { max. 1 sec warten! }
  500.     REPEAT Delay(1); Dec(t) UNTIL seite_da(0) or (t=0);
  501.   END;
  502.   gethead(0,sender);
  503.   IF activejobs[0].pg=0 THEN sperren(0);
  504.   IF nr=2 THEN name := configpath+'VT2.config'
  505.           ELSE name := configpath+'VT.config';
  506.   Reset(datei,name);
  507.   IF IOResult<>0 THEN BEGIN
  508.     Write(#155'2m"',name,'" nicht gefunden!');
  509.     Exit;
  510.   END;
  511.   Buffer(datei,500);
  512.   found := False; anything := False;
  513.   is_header := True;
  514.   WHILE NOT EoF(datei) DO BEGIN
  515.     ReadLn(datei,zeile);
  516.     t := Length(zeile); WHILE t>0 DO BEGIN
  517.       IF zeile[t]=' ' THEN zeile[t] := #0 ELSE t := 1;
  518.       Dec(t);
  519.     END;
  520.     IF zeile='' THEN
  521.       is_header := True { auf eine Leerzeile folgt ein Titel }
  522.     ELSE BEGIN
  523.       IF is_header THEN BEGIN
  524.         found := (Pos(zeile,sender)>0);
  525.         IF found THEN BEGIN
  526.           mainline; Write('hole '); IF nr>1 THEN Write(nr,'. ');
  527.           Write('Seitenauswahl f}r "',zeile,'"');
  528.           anything := True;
  529.         END;
  530.       END ELSE
  531.         IF found THEN add_job(zeile,True);
  532.       is_header := False;
  533.     END;
  534.   END;
  535.   IF NOT anything THEN Write('unbekannter Sender: "',Copy(sender,5,10),'"');
  536.   Close(datei);
  537.   redraw_queue(-1);
  538. END;
  539.  
  540. PROCEDURE edconfig{(nr: Integer)};
  541. VAR fenster: Text;
  542.     s: Str80;
  543. LIBRARY DosBase:  { Include-Files nein danke }
  544. -222 : FUNCTION  Execute(D1: Str; D2,D3: Long): Boolean;
  545. END;
  546. BEGIN
  547.   showscreen(False);
  548.   Reset(fenster,'CON:100/100/440/80/VT-Ausgabefenster');
  549.   IF nr=2 THEN s := editor + configpath + 'VT2.config'
  550.           ELSE s := editor + configpath + 'VT.config';
  551.   IF Execute(s,0,FileHandle(fenster)) THEN  Write('abgeschlossen')
  552.   ELSE  Write(#155'2mDOS-Fehler');
  553.   Close(fenster);
  554.   showscreen(True);
  555. END;
  556.  
  557. PROCEDURE dump_numbers;
  558. { Sendername und Seitennummern ins ClipBoard schreiben, Hilfe beim Erstellen }
  559. { der config-Dateien }
  560. VAR anz,nextnr,i: Integer;
  561.     hilf: p_onepage;
  562.     ok: Boolean;
  563.     s: str80;
  564. BEGIN
  565.   IF root=Nil THEN Exit;
  566.   anz := 0; hilf := root;
  567.   WHILE hilf<>Nil DO BEGIN
  568.     IF hilf^.next=Nil THEN nextnr := -1 ELSE nextnr := hilf^.next^.pg;
  569.     IF (hilf^.pg<$900) AND (hilf^.pg<>nextnr) THEN Inc(anz);
  570.     hilf := hilf^.next;
  571.   END;
  572.   start_clip(26+4*anz);
  573.   FOR i := 2 TO 25 DO BEGIN
  574.     s[i] := Chr(root^.chars[i+6]);
  575.     IF s[i]<' ' THEN s[i] := ' ';
  576.   END;
  577.   s[1] := #10; s[26] := #10; s[27] := #0;
  578.   clip_it(s,26);
  579.   hilf := root;
  580.   WHILE hilf<>Nil DO BEGIN
  581.     IF hilf^.next=Nil THEN nextnr := -1 ELSE nextnr := hilf^.next^.pg;
  582.     IF (hilf^.pg<$900) AND (hilf^.pg<>nextnr) THEN BEGIN
  583.       s := hexstr(hilf^.pg,3)+#10; clip_it(s,4);
  584.     END;
  585.     hilf := hilf^.next;
  586.   END;
  587.   end_clip;
  588. END;
  589.  
  590. BEGIN  { Initialisierungen }
  591.   editor := 'c:Ed '; { Editor für configs }
  592.   configpath := '';
  593.   toplevel := 4;  { nur Programm- und Blockseiten }
  594.   maxwait := 80;
  595.   burst := 0;
  596.   shuffle := 20;
  597. END.
  598.