home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1990 / 09 / tricks / isamtree.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1990-06-15  |  13.6 KB  |  595 lines

  1. (* ------------------------------------------------------ *)
  2. (*                       ISAMTREE.PAS                     *)
  3. (*     Unit zur Verwaltung indexsequentieller Dateien     *)
  4. (*   mit Hilfe von Indices, die als Binär-Baum verwaltet  *)
  5. (*      werden. ISAMTREE.PAS benötigt eine individuell    *)
  6. (*             erstellte Version von DEFINES.INC.         *)
  7. (*             (c)1990 Karlheinz Büker & TOOLBOX          *)
  8. (* ------------------------------------------------------ *)
  9. UNIT IsamTree;
  10.  
  11. INTERFACE
  12.  
  13. {$I Defines.inc}
  14.  
  15. TYPE
  16.   FileType = (Data, Index);
  17.  
  18.   KeyPtr   = ^KeyType;
  19.   KeyType  = RECORD
  20.     OB    : Key;      { deklariert in DEFINES.INC }
  21.     SetNr : WORD;     { Satznummer der Datendatei }
  22.     Left  : KeyPtr;   { Linkszeiger auf OB <= aktueller OB }
  23.     Right : KeyPtr;   { Rechtszeiger auf OB > aktueller OB }
  24.     END;
  25.  
  26. VAR
  27.   StartPtr  : KeyPtr;
  28.   NextPtr   : KeyPtr;
  29.   NextOB    : Key;
  30.   IsamError : BYTE;
  31.  
  32. FUNCTION  ExistFile (F : FileType) : BOOLEAN;
  33.           { TRUE, wenn Daten- bzw. Indexdatei existiert }
  34.  
  35. PROCEDURE CreateFile (F : FileType);
  36.           { erstellt neue Daten- bzw. Indexdatei }
  37.  
  38. PROCEDURE EraseFile (F : FileType);
  39.           { löscht Daten- bzw. Indexdatei }
  40.  
  41. PROCEDURE OpenDatabase;
  42.           { Öffnet Daten- und Indexdatei und }
  43.           { initialisiert Index-Tree im Heap }
  44.  
  45. PROCEDURE AddRecord (Data : DataType);
  46.           { Fügt Datensatz in die Indexdatei }
  47.           { und integriert den entspr. Key   }
  48.           { in den Tree im Heap              }
  49.  
  50. PROCEDURE GetRecord
  51.         (S : Key; VAR Data : DataType; VAR FilePos : WORD);
  52.         { FilePos wird nur zum evtl. Löschen }
  53.         { von Sätzen als Parameter benötigt. }
  54.         { Liefert den ersten Datensatz zurück, }
  55.         { dessen OB = S ist. }
  56.  
  57. PROCEDURE GetNextRecord
  58.         (VAR Data : DataType; VAR FilePos : WORD);
  59.         { Liefert den nächsten Datensatz,}
  60.         { dessen Ordnungsbegriff gleich  }
  61.         { dem zuletzt mit GetRecord oder }
  62.         { GetNextRecord gelesenen Daten- }
  63.         { satz ist. Diese Prozedur dient }
  64.         { zum Auffinden von Sätzen mit   }
  65.         { gleichen OBs. Ist DoubleAllowed}
  66.         { = False dann wird IsamError = 1}
  67.         { zurückgegeben }
  68.  
  69. PROCEDURE DelRecord (S : Key; VAR FilePos : WORD);
  70.         { Löscht Indexsatz S und kennzeichnet   }
  71.         { den Datensatz an FilePos als gelöscht.}
  72.         { FilePos wird als Parameter durch      }
  73.         { GetRecord zurückgeliefert             }
  74.  
  75. PROCEDURE ReorgDataFile;
  76.         { entfernen der als ungültig deklarierten }
  77.         { Sätze aus der Datendatei.               }
  78.  
  79. PROCEDURE Reko (Activate : BOOLEAN);
  80.         { löscht Schlüsseldatei und erstellt   }
  81.         { aus den Daten der Datendate eine neue}
  82.         { Schlüsseldatei. Wird Activate=TRUE   }
  83.         { übergeben, werden auch als gelöscht  }
  84.         { gekennzeichnete Sätze wieder Reakti- }
  85.         { viert                                }
  86.  
  87. PROCEDURE CloseDataBase;
  88. { Speichert Index-Tree und schließt Daten- und Indexdatei }
  89. IMPLEMENTATION
  90.  
  91. TYPE
  92.   IndexType = RECORD
  93.                 OB   : Key;
  94.                 SetNr : WORD;
  95.               END;
  96.   IFile     = FILE OF IndexType;
  97.  
  98. VAR
  99.   Next      : WORD;
  100.   HelpPtr   : KeyPtr;
  101.   OldExit   : Pointer;
  102.   DataFile  : FILE OF DataType;
  103.   IndexFile : IFile;
  104.  
  105. {-----------------------------------------}
  106.  
  107. FUNCTION Upper (S : STRING) : STRING;
  108. VAR a : BYTE;
  109. BEGIN
  110.   FOR a := 1 TO Length (S) DO
  111.   BEGIN
  112.     IF (S[a] >= 'a') AND (S[a] <= 'z')
  113.       THEN S[a] := Chr(Ord(S[a]) - 32)
  114.     ELSE IF S[a] = 'ä' THEN S[a] := 'Ä'
  115.     ELSE IF S[a] = 'ö' THEN S[a] := 'Ö'
  116.     ELSE IF S[a] = 'ü' THEN S[a] := 'Ü';
  117.   END;
  118.   Upper := S;
  119. END;
  120.  
  121. {-----------------------------------------}
  122.  
  123. FUNCTION Expand (S : STRING) : STRING;
  124. VAR a : BYTE;
  125. BEGIN
  126.   FOR a := 1 TO Length(S) DO
  127.   BEGIN
  128.     IF S[a] = 'ß' THEN
  129.     BEGIN
  130.       S[a] := 's'; Insert('s', S, a + 1);
  131.     END;
  132.     IF S[a] IN ['ä', 'Ä', 'ö', 'Ö', 'ü', 'Ü']
  133.     THEN BEGIN
  134.       CASE S[a] OF
  135.         'ä' : S[a] := 'a';
  136.         'Ä' : S[a] := 'A';
  137.         'ö' : S[a] := 'o';
  138.         'Ö' : S[a] := 'O';
  139.         'ü' : S[a] := 'u';
  140.         'Ü' : S[a] := 'U';
  141.       END;
  142.       IF S[a] IN ['a', 'o', 'u'] THEN
  143.         Insert('e', S, a + 1)
  144.         ELSE Insert('E', S, a + 1);
  145.     END;
  146.   END;
  147.   Expand := S;
  148. END;
  149.  
  150. {-----------------------------------------}
  151.  
  152. PROCEDURE SaveKey;
  153. VAR I : IndexType;
  154.  
  155.   PROCEDURE Save (P : KeyPtr);
  156.   BEGIN
  157.     IF P <> NIL THEN WITH P^ DO
  158.     BEGIN
  159.       Save(P^.Left);
  160.       I.OB    := P^.OB;
  161.       I.SetNr := P^.SetNr;
  162.       Write(IndexFile, I);
  163.       Save(P^.Right);
  164.       IF P <> NIL THEN Dispose(P);
  165.     END;
  166.   END;
  167.  
  168. BEGIN
  169.   IF StartPtr = NIL THEN Exit;
  170.   EraseFile(Index);
  171.   Rewrite(IndexFile);
  172.   Save(StartPtr);
  173.   StartPtr := NIL;
  174.   NextPtr := NIL;
  175. END;
  176.  
  177. {-----------------------------------------}
  178.  
  179. FUNCTION GetKey (OB : Key) : WORD;
  180. VAR Run   : KeyPtr;
  181.     SetNo : WORD;
  182.  
  183.   PROCEDURE Get (    OB   : Key;
  184.                  VAR Satz : WORD;
  185.                  VAR Run  : KeyPtr);
  186.   BEGIN
  187.     IF Run = NIL THEN
  188.     BEGIN
  189.       IsamError := 1; Satz := 0; Exit;
  190.     END
  191.     ELSE BEGIN
  192.       IF OB = Run^.OB THEN
  193.       BEGIN
  194.         IsamError := 0; Satz := Run^.SetNr;
  195.         NextPtr := Run^.Left; NextOB := OB;
  196.         Exit;
  197.       END
  198.       ELSE
  199.         IF OB > Run^.OB THEN
  200.           Get(OB, Satz, Run^.Right)
  201.       ELSE Get(OB, Satz, Run^.Left);
  202.     END;
  203.   END;
  204.  
  205. BEGIN
  206.   SetNo := 0;
  207.   IF ExpandOB THEN OB := Expand(OB);
  208.   IF IgnoreCase THEN OB := Upper(OB);
  209.   IF StartPtr = NIL THEN
  210.   BEGIN
  211.     IsamError := 1; Exit;
  212.   END
  213.   ELSE Run := StartPtr;
  214.   Get(OB, SetNo, Run);
  215.   GetKey := SetNo;
  216. END;
  217.  
  218. {-----------------------------------------}
  219.  
  220. PROCEDURE GetRecord(    S       : Key;
  221.                     VAR Data    : DataType;
  222.                     VAR FilePos : WORD);
  223. BEGIN
  224.   IF ExpandOB THEN S := Expand(s);
  225.   IF IgnoreCase THEN S := Upper(S);
  226.   IF Next = 0 THEN FilePos := GetKey(s);
  227.   Next := 0;
  228.   IF FilePos = 0 THEN
  229.   BEGIN
  230.     IsamError := 1; Exit;
  231.   END;
  232.   Seek(DataFile, FilePos - 1);
  233.   Read(DataFile, Data);
  234. END;
  235.  
  236. {-----------------------------------------}
  237.  
  238. PROCEDURE GetNextRecord(VAR Data:DataType;
  239. VAR FilePos : WORD);
  240. VAR FP : WORD;
  241. BEGIN
  242.   IF DoubleAllowed = FALSE THEN
  243.   BEGIN
  244.     IsamError := 1; Exit;
  245.   END;
  246.   HelpPtr := NextPtr;
  247.   IF HelpPtr = NIL THEN
  248.   BEGIN
  249.     IsamError := 1; Exit;
  250.   END
  251.   ELSE IF NextOB <> HelpPtr^.OB THEN
  252.   BEGIN
  253.     NextPtr := NIL; IsamError := 1; Exit;
  254.   END
  255.   ELSE
  256.   BEGIN
  257.     FP := HelpPtr^.SetNr;
  258.     IsamError := 0;
  259.     Next := FP;
  260.     GetRecord(HelpPtr^.OB, Data, FP);
  261.     NextPtr := HelpPtr^.Left;
  262.     FilePos := FP;
  263.   END;
  264. END;
  265.  
  266. {-----------------------------------------}
  267.  
  268. PROCEDURE Add (    Data    : DataType;
  269.                    FilePos : WORD;
  270.                VAR Run     : KeyPtr);
  271.   BEGIN
  272.     IF Run = NIL THEN
  273.     BEGIN
  274.       New(Run);
  275.       IF StartPtr = NIL THEN
  276.         StartPtr := Run;
  277.       IF Run = NIL THEN
  278.       BEGIN
  279.         IsamError := 255; Exit;
  280.       END;
  281.       Run^.OB    := Data.OB;
  282.       Run^.SetNr := FilePos;
  283.       Run^.Left  := NIL;
  284.       Run^.Right := NIL;
  285.     END
  286.     ELSE
  287.     BEGIN
  288.       IF Data.OB > Run^.OB THEN
  289.         Add (Data, FilePos, Run^.Right)
  290.       ELSE
  291.         Add (Data, FilePos, Run^.Left)
  292.     END;
  293.   END;
  294.  
  295. PROCEDURE AddRecord (Data : DataType);
  296. VAR FilePos : WORD;
  297.     Run     : KeyPtr;
  298.  
  299. BEGIN
  300.   IF (NOT DoubleAllowed) AND
  301.      (GetKey(Data.OB) > 0) THEN
  302.   BEGIN
  303.     IsamError := 2; Exit;
  304.   END;
  305.   Data.Valid := TRUE;
  306.   Seek(DataFile, FileSize(DataFile));
  307.   Write(DataFile, Data);
  308.   FilePos := System.FilePos(DataFile);
  309.   IF ExpandOB THEN
  310.     Data.OB := Expand(Data.OB);
  311.   IF IgnoreCase THEN
  312.     Data.OB := Upper(Data.OB);
  313.   Add(Data, FilePos, StartPtr);
  314. END;
  315.  
  316. {-----------------------------------------}
  317.  
  318. PROCEDURE InitKey;
  319. VAR  I : IndexType;
  320.      D : DataType;
  321.      Z : WORD;
  322.  
  323.   PROCEDURE ReadIndex (VAR F     : IFile;
  324.                            First, 
  325.                            Last : WORD);
  326.   VAR
  327.     Center : WORD;
  328.   BEGIN
  329.     Center := (First + Last) DIV 2;
  330.     Seek(F, Center);
  331.     Read(F, I);
  332.     D.OB := I.OB;
  333.     Add (D, I.SetNr, StartPtr);
  334.     IF Center > First THEN
  335.       ReadIndex(F, First, Center - 1);
  336.     IF Center < Last THEN
  337.       ReadIndex(F, Center + 1, Last);
  338.   END;
  339.  
  340. BEGIN
  341.   StartPtr := NIL;
  342.   Z := FileSize(Indexfile);
  343.   IF Z = 0 THEN Exit;
  344.   ReadIndex(IndexFile, 0, Z - 1);
  345. END;
  346.  
  347. {-----------------------------------------}
  348.  
  349. PROCEDURE DelRecord(    S : Key;
  350.                     VAR FilePos : WORD);
  351. VAR Data : DataType;
  352.     Run  : KeyPtr;
  353.     K    : Key;
  354.   PROCEDURE Del (OB : Key;VAR Go : KeyPtr);
  355.   VAR P : KeyPtr;
  356.  
  357.     PROCEDURE Kill (VAR Go : KeyPtr);
  358.     BEGIN
  359.       IF Go^.Right <> NIL THEN
  360.         Kill(Go^.Right)
  361.       ELSE BEGIN
  362.         P^.OB := Go^.OB;
  363.         P^.SetNr := Go^.SetNr;
  364.         P := Go;
  365.         Go := Go^.Left;
  366.         Dispose (P);
  367.       END;
  368.     END;  { Kill }
  369.  
  370.   BEGIN { Del }
  371.     IF Go = NIL THEN
  372.     BEGIN
  373.       IsamError := 1; Exit;
  374.     END
  375.     ELSE IF OB < Go^.OB THEN
  376.       Del(OB, Go^.Left)
  377.     ELSE IF OB > Go^.OB THEN
  378.       Del(OB, Go^.Right)
  379.     ELSE
  380.     BEGIN
  381.       P := Go;
  382.       IF P^.Right = NIL THEN Go := P^.Left
  383.       ELSE IF P^.Left = NIL THEN
  384.         Go := P^.Right
  385.       ELSE Kill(P^.Left);
  386.     END;
  387.   END;  { Del }
  388.  
  389. BEGIN { DelRecord }
  390.   IF ExpandOB THEN S := Expand(S);
  391.   IF IgnoreCase THEN S := Upper(S);
  392.   IF (FilePos = 0) OR (GetKey(S) = 0) THEN
  393.   BEGIN
  394.     IsamError := 1; Exit;
  395.   END;
  396.   Seek(DataFile, FilePos - 1);
  397.   Read (DataFile, Data);
  398.   K := Data.OB;
  399.   IF ExpandOB THEN K := Expand(K);
  400.   IF IgnoreCase THEN K := Upper(K);
  401.   IF K <> S THEN
  402.   BEGIN
  403.     IsamError := 1; Exit;
  404.   END;
  405.   Data.Valid := FALSE;
  406.   Seek(DataFile, FilePos - 1);
  407.   Write(DataFile, Data);
  408.   IsamError := IOResult;
  409.   IF StartPtr = NIL THEN
  410.   BEGIN
  411.     IsamError := 1; Exit;
  412.   END
  413.   ELSE Run := StartPtr;
  414.   Del(S, Run);
  415.   FilePos := 0;
  416. END;
  417.  
  418. {-----------------------------------------}
  419.  
  420. FUNCTION ExistFile(F : FileType) : BOOLEAN;
  421. VAR SF : FILE;
  422. BEGIN
  423.   ExistFile := FALSE;
  424.   CASE F OF
  425.     Data  : Assign (SF, FileName + '.DAT');
  426.     Index : Assign (SF, FileName + '.IDX');
  427.   END;
  428.   {$I-} Reset(SF); {$I+}
  429.   IF IOResult = 0 THEN
  430.   BEGIN
  431.     ExistFile := TRUE; Close (SF);
  432.   END;
  433. END;
  434.  
  435. {-----------------------------------------}
  436.  
  437. PROCEDURE CreateFile (F : FileType);
  438. BEGIN
  439.   {$I-}
  440.     CASE F OF
  441.       Data  : BEGIN
  442.                 Rewrite (Datafile);
  443.                 Close (DataFile);
  444.               END;
  445.       Index : BEGIN
  446.                 Rewrite (IndexFile);
  447.                 Close (IndexFile);
  448.               END;
  449.     END;
  450.   {$I+}
  451.   IsamError := IOResult;
  452. END;
  453.  
  454. {-----------------------------------------}
  455.  
  456. PROCEDURE EraseFile (F : FileType);
  457. BEGIN
  458.   {$I-}
  459.     CASE F OF
  460.       Data  : BEGIN
  461.                 Close (Datafile);
  462.                 Erase (Datafile);
  463.               END;
  464.       Index : BEGIN
  465.                 Close (IndexFile);
  466.                 Erase (IndexFile);
  467.               END;
  468.     END;
  469.   {$I+}
  470.   IsamError := IOResult;
  471. END;
  472.  
  473. {-----------------------------------------}
  474.  
  475. PROCEDURE OpenDatabase;
  476. VAR IOR : WORD;
  477. BEGIN
  478.   IOR := 0;
  479.   {$I-}
  480.     Reset (DataFile);
  481.     IOR := IOResult;
  482.     Reset (IndexFile);
  483.     IF IOR = 0 THEN IOR := IOResult;
  484.   {$I+}
  485.   IsamError := IOR;
  486.   IF IsamError <> 0 THEN Exit;
  487.   InitKey;
  488. END;
  489.  
  490. {-----------------------------------------}
  491.  
  492. PROCEDURE ReorgDataFile;
  493. VAR NewFile : FILE OF DataType;
  494.     Data    : DataType;
  495. BEGIN
  496.   IF StartPtr = NIL THEN
  497.   BEGIN
  498.     IsamError := 1; Exit;
  499.   END;
  500.   SaveKey;
  501.   Assign(NewFile, FileName + '.NEW');
  502.   Rewrite(NewFile);
  503.   Seek(DataFile, 0);
  504.   While NOT EoF(DataFile) DO
  505.   BEGIN
  506.     Read(DataFile, Data);
  507.     IF Data.Valid = TRUE THEN
  508.       Write(NewFile, Data);
  509.   END;
  510.   Close (DataFile); Close (NewFile);
  511.   Erase (DataFile);
  512.   Rename (NewFile, FileName + '.DAT');
  513.   Reset (DataFile);
  514.   Reko(FALSE);
  515. END;
  516.  
  517. {-----------------------------------------}
  518.  
  519. PROCEDURE Reko (Activate : BOOLEAN);
  520. VAR Run    : KeyPtr;
  521.     Data   : DataType;
  522.     OBSave : Key;
  523. BEGIN
  524.   SaveKey;
  525.   StartPtr := NIL;
  526.   Seek(DataFile, 0);
  527.   While NOT EoF(DataFile) DO
  528.   BEGIN
  529.     Read(DataFile, Data);
  530.     IF Data.Valid OR
  531.       ((NOT Data.Valid) AND Activate) THEN
  532.     BEGIN
  533.       Run := StartPtr;
  534.       OBSave := Data.OB;
  535.       IF IgnoreCase THEN Data.OB := Upper(Data.OB);
  536.       IF ExpandOB THEN Data.OB := Expand(Data.OB);
  537.       Add(Data, System.FilePos(DataFile), Run);
  538.       Data.OB := OBSave;
  539.     END;
  540.     IF (NOT Data.Valid) AND Activate THEN
  541.     BEGIN
  542.       Seek(DataFile, System.FilePos(DataFile) - 1);
  543.       Data.Valid := TRUE;
  544.       Write(DataFile, Data);
  545.     END;
  546.   END;
  547. END;
  548.  
  549. {-----------------------------------------}
  550.  
  551. PROCEDURE CloseDatabase;
  552. VAR IOR : WORD;
  553. BEGIN
  554.   SaveKey;
  555.   IOR := 0;
  556.   {$I-}
  557.     Close (DataFile);
  558.     IOR := IOResult;
  559.     Close (IndexFile);
  560.     IF IOR = 0 THEN IOR := IOResult;
  561.   {$I+}
  562.   IsamError := IOR;
  563. END;
  564.  
  565. {-----------------------------------------}
  566.  
  567. {$F+}
  568. FUNCTION HeapFunc (Size : WORD) : INTEGER;
  569. BEGIN
  570.   IsamError := 1; HeapFunc := 1;
  571. END;
  572. {$F-}
  573.  
  574. {-----------------------------------------}
  575.  
  576. {$F+}
  577. PROCEDURE NewExit;
  578. BEGIN
  579.   CloseDataBase;
  580.   ExitProc := OldExit;
  581. END;
  582. {$F-}
  583.  
  584. {-----------------------------------------}
  585.  
  586. BEGIN { Initialisierungsteil }
  587.   StartPtr  := NIL; HelpPtr   := NIL;
  588.   NextPtr   := NIL; OldExit   := ExitProc;
  589.   ExitProc  := @NewExit; Next := 0;
  590.   HeapError := @HeapFunc;
  591.   IsamError := 0;
  592.   Assign (DataFile, FileName + '.DAT');
  593.   Assign (IndexFile, FileName + '.IDX');
  594. END.  { Initialisierungsteil }
  595.