home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / spezial / 22 / buffer / diskbuf.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1991-01-04  |  14.1 KB  |  454 lines

  1. (* ----------------------------------------------------- *)
  2. (*                    DISKBUF.PAS                        *)
  3. (*                                                       *)
  4. (* ■ DiskBuffer: Lagert Daten, die nicht mehr in Heap auf*)
  5. (*   Diskette oder Festplatte aus. Diese Vorgänge laufen *)
  6. (*   automatisch intern ab; es sei denn, es tritt ein    *)
  7. (*   Fehler beim Lesen/Schreiben statt, dann können z.B. *)
  8. (*   keine neuen Zeilen mehr angehängt werden.           *)
  9. (*                                                       *)
  10. (*             (c) 1991 by R.Reichert & toolbox          *)
  11. (* ----------------------------------------------------- *)
  12. UNIT DiskBuf;
  13.  
  14. INTERFACE
  15.  
  16. USES UBuffer;
  17.  
  18. CONST
  19.   BufDiskFull = 10;
  20.   BufFileErr  = 11;
  21.  
  22. TYPE
  23.   DiskBufferPtr = ^DiskBuffer;
  24.   DiskBuffer    = OBJECT (Buffer)
  25.  
  26.       AllSaved,                   { Alles gespeichert ?   }
  27.       SaveData : BOOLEAN;         { File löschen ?        }
  28.       BufDosErr: BYTE;            { Dos-Fehlercode        }
  29.       SEFileName,               { Dateiname zum Auslagern }
  30.       EndName,     { Name falls Daten endgültig speichern }
  31.       SEPath   : STRING;       { Laufwerk und Verzeichnis }
  32.       f        : FILE;
  33.  
  34.       CONSTRUCTOR Init
  35.         (MC, ML, BegLines : WORD; FrHeap : LONGINT);
  36.       PROCEDURE ErrorHandling (Nr : WORD);         VIRTUAL;
  37.       {---------- Interne Methoden zum Auslagern: --------}
  38.       PROCEDURE NewLines (Num : WORD);             VIRTUAL;
  39.       PROCEDURE KillLines (Num : WORD);            VIRTUAL;
  40.       PROCEDURE SaveAll;                           VIRTUAL;
  41.       PROCEDURE SaveFrom (y : WORD);               VIRTUAL;
  42.       PROCEDURE SaveLine (y : WORD);               VIRTUAL;
  43.       PROCEDURE SaveNewLine
  44.         (y : WORD; VAR Line : OneLine);            VIRTUAL;
  45.       PROCEDURE SaveNewDrive (NewDrive : STRING);  VIRTUAL;
  46.       PROCEDURE Flush;                             VIRTUAL;
  47.       PROCEDURE LoadLine
  48.         (y : WORD; VAR Line : OneLine);            VIRTUAL;
  49.       PROCEDURE LoadPart (y1, y2 : WORD);          VIRTUAL;
  50.       PROCEDURE CleanMem;                          VIRTUAL;
  51.       PROCEDURE CloseFile;                         VIRTUAL;
  52.       {--------- Methoden für "Aussenwelt": --------------}
  53.       PROCEDURE WriteStrXY
  54.         (x, y : WORD; Str : STRING);               VIRTUAL;
  55.       PROCEDURE SetSaveData (SD : BOOLEAN);        VIRTUAL;
  56.       PROCEDURE SetEndFileName (EFN : STRING);     VIRTUAL;
  57.       PROCEDURE SetSaveExtPath (Path : STRING);    VIRTUAL;
  58.  
  59.       FUNCTION GetAllSaved : BOOLEAN;              VIRTUAL;
  60.       FUNCTION GetSaveData : BOOLEAN;              VIRTUAL;
  61.       FUNCTION GetErrorL1 : WORD;                  VIRTUAL;
  62.       FUNCTION GetDosErr : WORD;                   VIRTUAL;
  63.       DESTRUCTOR Done;                             VIRTUAL;
  64.     END;
  65.  
  66. IMPLEMENTATION
  67.  
  68. CONSTRUCTOR DiskBuffer.Init
  69.               (MC, ML, BegLines : WORD; FrHeap : LONGINT);
  70. BEGIN
  71.   IF Buffer.Init (MC, ML, BegLines, Frheap) THEN BEGIN
  72.     AllSaved  := FALSE;  SaveData := FALSE;
  73.     BufDosErr := 0;
  74.     SEFilename:= '';     EndName  := '';
  75.     SEPath    := '';
  76.   END ELSE
  77.     Fail;
  78. END;
  79.  
  80. PROCEDURE DiskBuffer.ErrorHandling (Nr : WORD);
  81. BEGIN
  82.     { BufErrorL1: Nur DISKETTENFEHLER,
  83.       BufErrorL2: alle anderen Fehler. }
  84.   IF (Nr=BufDiskFull) OR
  85.      (Nr=BufFileErr) THEN
  86.     BufErrorL1 := Nr
  87.   ELSE
  88.     BufErrorL2 := Nr;
  89. END;
  90.  
  91. PROCEDURE DiskBuffer.KillLines (Num : WORD);
  92.   VAR TempLines, l, i : WORD;
  93. BEGIN
  94.   TempLines := Lines;
  95.   Lines := Lines-Num;
  96.   FOR i := TempLines DOWNTO Succ (Lines) DO
  97.     IF (TextBuf^[i] <> NIL) THEN BEGIN
  98.       FreeMem (TextBuf^[i], 2 * Succ (MaxColumns));
  99.       TextBuf^[i] := NIL;
  100.     END ELSE
  101.       IF (AllSaved) AND
  102.          (BufErrorL1<>BufFileErr) THEN BEGIN
  103.         Seek (f, i);
  104.         l := filesize (f);
  105.         Truncate (f); l := filesize(f);
  106.         l := filePos(f);
  107.         IF BufErrorL1=BufDiskFull THEN
  108.           BufErrorL1 := BufOk;
  109.       END;
  110. END;
  111.  
  112. PROCEDURE DiskBuffer.NewLines (Num : WORD);
  113.   VAR i,
  114.       TLines : WORD;
  115.       MemLimit : LONGINT;
  116.       DL : WORD; l : integer;
  117. BEGIN
  118.   TLines := Lines;
  119.   Lines := Lines+Num;
  120.   DL := 0;
  121.   MemLimit  := 2 * Succ (MaxColumns) + FreeHeap;
  122.   FOR i := Succ (TLines) TO Lines DO
  123.     IF (MemAvail > MemLimit) THEN BEGIN
  124.       GetMem (TextBuf^[i], 2 * Succ (MaxColumns));
  125.       GetNewLine (Attr, TextBuf^[i]^);
  126.     END ELSE BEGIN
  127.       IF (NOT AllSaved) THEN
  128.         SaveAll;
  129.       IF GetErrorL1=BufOk THEN BEGIN
  130.         GetNewLine (Attr, TempLines [SetMLTL]^);
  131.         l := filesize (f);
  132.         SaveNewLine (i, TempLines [SetMLTL]^);
  133.       END ELSE
  134.         Inc (DL);
  135.     END;
  136.   Dec (Lines, DL);
  137. END;
  138.  
  139. (* ----------------------------------------------------- *)
  140. (* Bildet einen Dateinamen aus der aktuellen Uhrzeit. In *)
  141. (* diese temporäre Datei wird ausgelagert.               *)
  142. (* ----------------------------------------------------- *)
  143. PROCEDURE DiskBuffer.SaveAll;
  144. BEGIN
  145.   AllSaved := FALSE;
  146.   Str (Time, SEFileName);
  147.   IF Length (SEFileName) > 8 THEN
  148.     Delete (SEFileName, 1, Length(SEFileName)-8);
  149.   IF (SEPath<>'') AND
  150.      (SEPath [Length (SEPath)]<>'\') AND
  151.      (SEPath [Length (SEPath)]<>':') THEN
  152.     SEPath := SEPath+'\';
  153.   SEFileName := SEPath+SEFileName+'.$$$';
  154. {$I-}
  155.   Assign (f, SEFileName);
  156.   ReWrite (f, Succ (MaxColumns)*2);
  157. {$I+}
  158.   BufDosErr := IoResult;
  159.   IF BufDosErr<>0 THEN
  160.     ErrorHandling (BufFileErr)
  161.   ELSE BEGIN
  162.     AllSaved := TRUE;
  163.     SaveFrom (0);
  164.   END;
  165. END;
  166.  
  167. PROCEDURE DiskBuffer.SaveFrom (y : WORD);
  168.   VAR i : WORD;
  169. BEGIN
  170.   IF AllSaved THEN BEGIN     { schon einmal gespeichert ? }
  171.     i := y;
  172.     IF (BufErrorL1<>BufFileErr) THEN
  173.       WHILE (NOT (i>Lines)) AND
  174.             (BufErrorL1<>BufDiskFull) DO BEGIN
  175.         SaveLine (i);             { Zeilenweise speichern }
  176.         Inc (i);
  177.       END;
  178.   END;
  179. END;
  180.  
  181. (* ----------------------------------------------------- *)
  182. (* Speichert eine Zeile aus dem Speicher ab. Prüft nur,  *)
  183. (* ob Zeile nicht ausgelagert ist, nimmt aber keine Be-  *)
  184. (* reichsüberprüfung vor. Als 0.te Zeile wird InfoLine   *)
  185. (* gespeichert.                                          *)
  186. (* ----------------------------------------------------- *)
  187. PROCEDURE DiskBuffer.SaveLine (y : WORD);
  188. BEGIN
  189.   IF (AllSaved) AND
  190.      (BufErrorL1<>BufFileErr) AND
  191.      (y>=0) AND (y<=Lines) THEN BEGIN
  192.   {$I-}
  193.     Seek (f, y);
  194.     IF (y=0) THEN
  195.       BlockWrite (f, InfoLine^, 1)
  196.     ELSE
  197.       IF (TextBuf^[y]<>NIL) THEN
  198.         BlockWrite (f, TextBuf^[y]^, 1);
  199.   {$I+}
  200.     BufDosErr := IoResult;
  201.     IF (BufDosErr <> 0) THEN
  202.       Errorhandling (BufDiskFull);
  203.   END;
  204. END;
  205.  
  206. (* ----------------------------------------------------- *)
  207. (* Speichert an y die übergebene Zeile Line ab. Hier wird*)
  208. (* auf Bereichsgültigkeit und Dateifehler geprüft. Wenn  *)
  209. (* die Zeile y nicht ausgelagert ist, wird Line nicht auf*)
  210. (* Diskette gespeichert, sondern im Speicher abgelegt.   *)
  211. (* ----------------------------------------------------- *)
  212. PROCEDURE DiskBuffer.SaveNewLine (y : WORD;
  213.                                   VAR Line : OneLine);
  214. BEGIN
  215.   IF (XYInBuf (1, y)) AND (AllSaved) AND
  216.      (TextBuf^[y]=NIL) AND
  217.      (BufErrorL1 <> BufFileErr) THEN BEGIN
  218.   {$I-}
  219.     Seek (f, y);
  220.     BlockWrite (f, Line, 1);
  221.   {$I+}
  222.     BufDosErr := IoResult;
  223.     IF (BufDosErr <> 0) THEN
  224.       Errorhandling (BufDiskFull);
  225.   END;
  226.   IF (XYInBuf (1, y)) AND
  227.      (TextBuf^[y]<>NIL) THEN
  228.     Move (Line, TextBuf^[y]^, 2 * Succ (Columns));
  229. END;
  230.  
  231. (* ----------------------------------------------------- *)
  232. (* Falls eine Diskette voll ist, kann mit SaveNewDrive   *)
  233. (* auf einen anderen Datenträger gespeichert werden.     *)
  234. (* ----------------------------------------------------- *)
  235. PROCEDURE DiskBuffer.SaveNewDrive (NewDrive : STRING);
  236. BEGIN
  237.   IF AllSaved THEN BEGIN
  238.     BufErrorL1 := BufOk;            { Fehler zurücksetzen }
  239.   {$I-}
  240.     Close (f);
  241.   {$I+}
  242.     SEPath := NewDrive;  AllSaved := FALSE;
  243.     SaveAll;
  244.   END;
  245. END;
  246.  
  247. (* ----------------------------------------------------- *)
  248. (* Bildet die Turbo-Prozedur Flush () nach, die nur für  *)
  249. (* Textdateien gültig ist.                               *)
  250. (* ----------------------------------------------------- *)
  251. PROCEDURE DiskBuffer.Flush;
  252. BEGIN
  253.   IF (AllSaved) AND
  254.      (BufErrorL1<>BufFileErr) THEN BEGIN
  255.     Close (f);
  256.     ReSet (f, 2 * Succ (MaxColumns));
  257.   END;
  258. END;
  259.  
  260. (* ----------------------------------------------------- *)
  261. (* Lädt eine Zeile aus Datei oder aus Speicher           *)
  262. (* ----------------------------------------------------- *)
  263. PROCEDURE DiskBuffer.LoadLine (y : WORD;
  264.                               VAR Line : OneLine);
  265. BEGIN
  266.   IF (y>=0) AND (y<=Lines) AND
  267.      (AllSaved) AND
  268.      (BufErrorL1 <> BufFileErr) AND
  269.      (TextBuf^[y]=NIL) THEN BEGIN
  270.   {$I-}
  271.     Seek (f, y);
  272.     BlockRead (f, Line, 1);
  273.   {$I+}
  274.     BufDosErr := IoResult;
  275.     IF BufDosErr<>0 THEN
  276.       ErrorHandling (BufFileErr);
  277.   END ELSE BEGIN
  278.     IF y>Lines THEN
  279.       NewLines (Lines-y);
  280.     IF (TextBuf^[y] <> NIL) THEN
  281.       Move (TextBuf^[y]^, Line, 2 * Succ (Columns));
  282.   END;
  283. END;
  284.  
  285. (* ----------------------------------------------------- *)
  286. (* Lädt (aus ausgelagerter Datei) den Teil von y1 bis y2,*)
  287. (* sofern möglich. Dafür werden vor und hinter diesem    *)
  288. (* Teilstück Zeilen ausgelagert. Diese Prozedur ist dazu *)
  289. (* da, dass ein Teil geladen werden kann für anschliessen*)
  290. (* de Bearbeitung, ohne dauernd jede Zeile einzeln laden *)
  291. (* zu müssen.                                            *)
  292. (* ----------------------------------------------------- *)
  293. PROCEDURE DiskBuffer.LoadPart (y1, y2 : WORD);
  294.   VAR i, j, No : WORD;
  295.  
  296.   (* --------------------------------------------------- *)
  297.   (*   Diese Prozedur sucht den Bereich zw BegCol und    *)
  298.   (*   EndCol nach Zeilen ab, die ausgelagert werden     *)
  299.   (*   können. Max enthält die maximale Anzahl Zeilen,   *)
  300.   (*   die ausgelagert werden sollen, Counter gibt die   *)
  301.   (*   Anzahl der tatsächlich ausgelagerten Zeilen zu-   *)
  302.   (*   rück, da nicht immer Max Zeilen gefunden werden   *)
  303.   PROCEDURE SearchSave (BegCol, EndCol, Max : WORD;
  304.                         VAR Counter : WORD);
  305.     VAR i : WORD;
  306.   BEGIN
  307.     i := BegCol;
  308.     WHILE NOT (i > EndCol) AND
  309.           NOT (Counter >= Max) DO BEGIN
  310.       IF TextBuf^[i] <> NIL THEN BEGIN
  311.         SaveLine (i);         Inc (Counter);
  312.         FreeMem (TextBuf^[i], 2 * Succ (MaxColumns));
  313.         TextBuf^[i] := NIL;
  314.       END;
  315.       Inc (i);
  316.     END;
  317.   END;
  318.  
  319. BEGIN  {  LoadPart  }
  320.   IF y1<1 THEN y1 := 1;
  321.   IF y2>Lines THEN y2 := Lines;
  322.   IF (AllSaved) AND
  323.      (BufErrorL1 <> BufFileErr) AND
  324.      (BufErrorL2 <> BufDiskFull) THEN BEGIN
  325.     No := 0; j := 0;
  326.     FOR i := y1 TO y2 DO
  327.       IF TextBuf^[i]=NIL THEN
  328.         Inc (No);
  329.     SearchSave (1, y1, No, j);
  330.     IF j > 0 THEN
  331.       j := j;
  332.     SearchSave (Succ (y2), Lines, No, j);
  333.     IF j = 0 THEN
  334.       j := j;
  335.     IF MemAvail>FreeHeap+2*Succ (MaxColumns)*j THEN
  336.       Inc (j, (MemAvail-FreeHeap-
  337.                2*Succ (MaxColumns)*j) DIV
  338.               (2 * Succ (MaxColumns)));
  339.     i := y1; No := 0;
  340.     WHILE NOT (i > y2) AND
  341.           NOT (No >= j) DO BEGIN
  342.       IF TextBuf^[i]=NIL THEN BEGIN
  343.         LoadLine (i, TempLines [LPTL]^);
  344.         Inc (No);
  345.         GetMem (TextBuf^[i], 2 * Succ (MaxColumns));
  346.         Move (TempLines [LPTL]^, TextBuf^[i]^,
  347.               2 * Succ (Columns));
  348.       END;
  349.       Inc (i);
  350.     END;
  351.   END;
  352. END;
  353.  
  354. (* ----------------------------------------------------- *)
  355. (* Speichert gesamten sich im Speicher befindenden Puffer*)
  356. (* auf Diskette und löscht in aus dem Speicher (im Gegen-*)
  357. (* satz zu SaveLine/SaveNewLine).                        *)
  358. (* ----------------------------------------------------- *)
  359. PROCEDURE DiskBuffer.CleanMem;
  360.   VAR i : WORD;
  361. BEGIN
  362.   IF GetAllSaved THEN SaveFrom (0)
  363.                  ELSE SaveAll;
  364.   IF GetErrorL1=0 THEN
  365.     FOR i := 1 TO Lines DO
  366.       IF TextBuf^[i]<>NIL THEN BEGIN
  367.         FreeMem (TextBuf^[i], 2*Succ (MaxColumns));
  368.         TextBuf^[i] := NIL;
  369.       END;
  370. END;
  371.  
  372. (* ----------------------------------------------------- *)
  373. (* Wenn SaveData FALSE ist, wird die temporäre Datei ge- *)
  374. (* löscht, ansonsten alles nochmal gespeichert und wenn  *)
  375. (* EndName<>'' ist, die Datei in EndName umbenannt.      *)
  376. (* ACHTUNG: Nur am Ende von Done aus aufrufen !          *)
  377. (* ----------------------------------------------------- *)
  378. PROCEDURE DiskBuffer.CloseFile;
  379. BEGIN
  380.   IF AllSaved THEN BEGIN
  381.     IF SaveData THEN SaveFrom (0);
  382.   {$I-}
  383.     Close (f);
  384.   {$I+}
  385.     BufDosErr := IoResult;
  386.     IF (BufDosErr<>0) THEN
  387.       ErrorHandling (BufFileErr)
  388.     ELSE BEGIN
  389.       IF (NOT SaveData) AND (EndName='') THEN
  390.         Erase (f)       { wenn nicht retten, dann löschen }
  391.       ELSE IF EndName<>'' THEN
  392.         Rename (f, EndName);            { oder umbenennen }
  393.              { ACHTUNG: Es darf keine Datei mit dem Namen
  394.                EndName existieren, sonst bleibt die Umbe-
  395.                nennung erfolglos.                         }
  396.     END;
  397.   END;
  398. END;
  399.  
  400. PROCEDURE DiskBuffer.WriteStrXY (x,y : WORD; Str : STRING);
  401. BEGIN
  402.   IF (y=Succ (Lines)) AND
  403.      (MemAvail-FreeHeap<2*Succ (MaxColumns)) AND
  404.      (NOT AllSaved) THEN
  405.     SaveAll;
  406.   Buffer.WriteStrXY (x, y, Str);
  407. END;
  408.  
  409. PROCEDURE DiskBuffer.SetSaveData (SD : BOOLEAN);
  410. BEGIN
  411.   SaveData := SD;
  412. END;
  413.  
  414. PROCEDURE DiskBuffer.SetEndFileName (EFN : STRING);
  415. BEGIN
  416.   Endname := EFN;
  417. END;
  418.  
  419. PROCEDURE DiskBuffer.SetSaveExtPath (Path : STRING);
  420. BEGIN
  421.   SEPath := Path;
  422. END;
  423.  
  424. FUNCTION DiskBuffer.GetAllSaved : BOOLEAN;
  425. BEGIN
  426.   GetAllSaved := AllSaved;
  427. END;
  428.  
  429. FUNCTION DiskBuffer.GetSaveData : BOOLEAN;
  430. BEGIN
  431.   GetSaveData := SaveData;
  432. END;
  433.  
  434. FUNCTION DiskBuffer.GetErrorL1 : WORD;
  435. BEGIN
  436.   GetErrorL1 := BufErrorL1;
  437. END;
  438.  
  439. FUNCTION DiskBuffer.GetDosErr : WORD;
  440. BEGIN
  441.   GetDosErr := BufDosErr;
  442. END;
  443.  
  444. DESTRUCTOR DiskBuffer.Done;
  445. BEGIN
  446.   CloseFile;
  447.   Buffer.Done;
  448. END;
  449.  
  450. END.
  451. (* ----------------------------------------------------- *)
  452. (*                 Ende von DISKBUF.PAS                  *)
  453. (* ----------------------------------------------------- *)
  454.