home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / database / oodb / oodb.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-07-13  |  25.3 KB  |  747 lines

  1. unit OODB;
  2.  
  3. interface
  4.  
  5.    uses Objects;
  6.  
  7.    const
  8.       PIDLimit: Word = $7FFF;
  9.       Delta = 4;
  10.       Hallmark = 9999;
  11.       IndexPointerLocation = 4;
  12.       StorageStart = 8;
  13.  
  14.    type
  15.  
  16.       { Record type for object registration }
  17.  
  18.       IndRec =
  19.          record
  20.             ID        : Word;
  21.             StartPos,
  22.             Size      : Longint;
  23.             Base      : Integer
  24.          end;
  25.       PIndRec = ^IndRec;
  26.  
  27.       { Stream for object size evaluation }
  28.  
  29.       TNullStream =
  30.          object (TStream)
  31.             SizeCounter : Longint;
  32.             constructor Init;
  33.             procedure   ResetCounter;                   virtual;
  34.             procedure   Write (var Buf; Count: Word);   virtual;
  35.             function    SizeInStream: Longint;          virtual;
  36.          end;
  37.       PNullStream = ^TNullStream;
  38.  
  39.       { Stream - database main storage }
  40.  
  41.       DBStream = TStream;
  42.       PDBStream = ^DBStream;
  43.  
  44.       { Collection for indexes }
  45.  
  46.       TIndexCollection =
  47.          object (TCollection)
  48.             procedure FreeItem (Item: Pointer);                 virtual;
  49.             function  GetItem (var S: TStream): Pointer;        virtual;
  50.             procedure PutItem (var S: TStream; Item: Pointer);  virtual;
  51.          end;
  52.       PIndexCollection = ^TIndexCollection;
  53.  
  54.       { --- TBASE - the main class --- }
  55.  
  56.       TBase =
  57.          object (TObject)
  58.  
  59.             BaseStream : PDBStream;         { Main storage pointer }
  60.             DBIndex,                        { Database index }
  61.             HolesIndex : PIndexCollection;  { Holes index }
  62.             PIDCurrent : Word;              { Unique identifier }
  63.             NS         : PNullStream;       { For object size evaluation }
  64.             DoneFlag   : Boolean;           { True if OODB is being disposed }
  65.  
  66.             function  BytesInStream (P: PObject): Longint ;
  67.                                virtual;
  68.             procedure IndexSort (Cat: PIndexCollection; StOrd: Boolean);
  69.                                virtual;
  70.             function  IndexFound (Cat: PIndexCollection;
  71.                                   LookFor: Longint;
  72.                                   var Pos: Integer;
  73.                                   PIDSorted: Boolean): Boolean;
  74.                                virtual;
  75.             function  HoleFound (S: Longint; var Pos: Longint): Boolean;
  76.                                virtual;
  77.  
  78.             procedure   Abort;                          virtual;
  79.             procedure   Commit;                         virtual;
  80.             constructor Init (AStream: PDBStream);
  81.             destructor  Done;                           virtual;
  82.             function    Create: Word;                   virtual;
  83.             procedure   Put (PID: Word; P: PObject);    virtual;
  84.             function    Get (PID: Word): PObject;       virtual;
  85.             procedure   Destroy (PID: Word);            virtual;
  86.  
  87.             function    ObjSize (PID: Word): Longint;   virtual;
  88.             function    Count: Integer;                 virtual;
  89.  
  90.             procedure   IdlePack;                       virtual;
  91.  
  92.          end; { -- TBase -- }
  93.       PBase = ^TBase;
  94.  
  95. implementation
  96.  
  97.    { -- Implementation of TNullStream -- }
  98.  
  99.    constructor TNullStream.Init;
  100.       begin
  101.          TStream.Init;
  102.          ResetCounter
  103.       end;
  104.  
  105.    procedure TNullStream.ResetCounter;
  106.       begin
  107.          SizeCounter := 0
  108.       end;
  109.  
  110.    procedure TNullStream.Write (var Buf; Count: Word);
  111.       { Overrides TStream.Write method }
  112.       begin
  113.          SizeCounter := SizeCounter + Count
  114.       end;
  115.  
  116.    function TNullStream.SizeInStream: Longint;
  117.       begin
  118.          SizeInStream := SizeCounter
  119.       end;
  120.  
  121.    { -- End of TNullStream implementation -- }
  122.  
  123.    { -- Implementation of TIndexCollection -- }
  124.  
  125.    procedure TIndexCollection.FreeItem (Item: Pointer);
  126.  
  127.       begin
  128.          Dispose (Item)
  129.       end;  { FreeItem }
  130.  
  131.    function TIndexCollection.GetItem (var S: TStream): Pointer;
  132.  
  133.       var Item : PIndRec;
  134.  
  135.       begin
  136.          New (Item);
  137.          with S do
  138.               with Item^ do
  139.                    begin
  140.                       Read (ID, SizeOf(ID));
  141.                       Read (StartPos, SizeOf(StartPos));
  142.                       Read (Size, SizeOf(Size));
  143.                       Read (Base, SizeOf(Base))
  144.                    end;
  145.          GetItem := Item
  146.       end;  { GetItem }
  147.  
  148.    procedure TIndexCollection.PutItem (var S: TStream; Item: Pointer);
  149.  
  150.       begin
  151.          with S do
  152.               with IndRec(Item^) do
  153.                    begin
  154.                       Write (ID, SizeOf(ID));
  155.                       Write (StartPos, SizeOf(StartPos));
  156.                       Write (Size, SizeOf(Size));
  157.                       Write (Base, SizeOf(Base))
  158.                    end
  159.       end;  { PutItem }
  160.  
  161.    { -- End of TIndexCollection implementation -- }
  162.  
  163.    { -- TBASE IMPLEMENTATION -- }
  164.  
  165.    { ----- BytesInStream ------------------------------------------ }
  166.  
  167.    function TBase.BytesInStream (P: PObject): Longint ;
  168.  
  169.    { Determines the number of bytes required
  170.      to put an object into the stream }
  171.  
  172.       begin
  173.          with NS^ do
  174.               begin
  175.                  ResetCounter;
  176.                  Put (P);
  177.                  BytesInStream := SizeInStream
  178.               end
  179.       end;
  180.  
  181.    { ----- IndexSort ---------------------------------------------- }
  182.  
  183.    procedure TBase.IndexSort (Cat: PIndexCollection; StOrd: Boolean);
  184.  
  185.    { Bubble-sorts any index (DBIndex or HolesIndex) according either to
  186.      StartPos'es in a stream (StOrd = True) or to PID's (StOrd = False) }
  187.  
  188.       var
  189.          i, j, k : Integer;
  190.          Min     : Longint;
  191.          Aux     : PIndRec;
  192.  
  193.       begin
  194.  
  195.          with Cat^ do
  196.  
  197.               for i := 0 to Count-2 do
  198.  
  199.                   begin
  200.                      if StOrd
  201.                         then begin
  202.                                 Min := IndRec(At(i)^).StartPos; k := i;
  203.                                 for j := i+1 to Count-1 do
  204.                                     if IndRec(At(j)^).StartPos < Min
  205.                                         then begin
  206.                                                 k := j;
  207.                                                 Min := IndRec(At(k)^).StartPos
  208.                                              end
  209.                              end
  210.                         else begin
  211.                                 Min := IndRec(At(i)^).ID; k := i;
  212.                                 for j := i+1 to Count-1 do
  213.                                     if IndRec(At(j)^).ID < Min
  214.                                        then begin
  215.                                                k := j;
  216.                                                Min := IndRec(At(k)^).ID
  217.                                             end
  218.                              end;
  219.                      Aux := At (i);
  220.                      AtPut (i,At(k)); AtPut (k,Aux)    { Bubble is up }
  221.                   end  { for }
  222.  
  223.       end; { IndexSort }
  224.  
  225.    { ----- IndexFound --------------------------------------------- }
  226.  
  227.    function TBase.IndexFound
  228.                   (Cat: PIndexCollection; LookFor: Longint;
  229.                    var Pos: Integer; PIDSorted: Boolean)    : Boolean;
  230.  
  231.    { Looks for LookFor in Cat^ index (binary search) and returns True
  232.      if hits it. Position for LookFor (Pos) is located by all means }
  233.  
  234.       var
  235.          m, j  : Integer;
  236.          Value : Longint;     { Value that is found }
  237.  
  238.       begin
  239.  
  240.          IndexFound := False;
  241.          with Cat^ do
  242.               begin
  243.                  Pos := 0; j := Count-1;
  244.                  if j < Pos
  245.                     then Exit;
  246.                  while j > Pos do
  247.                        begin
  248.                           m := ( Pos + j ) div 2;
  249.                           if ( PIDSorted and
  250.                                (IndRec(At(m)^).ID >= LookFor) )
  251.                              or
  252.                              ( not PIDSorted and
  253.                                (IndRec(At(m)^).StartPos >= LookFor) )
  254.                              then j := m
  255.                              else Pos := m + 1
  256.                        end; { while }
  257.                  if PIDSorted
  258.                     then Value := IndRec(At(Pos)^).ID
  259.                     else Value := IndRec(At(Pos)^).StartPos;
  260.                  if Value < LookFor
  261.                     then Pos := Pos + 1
  262.                     else if Value = LookFor
  263.                             then IndexFound := True
  264.               end  { with }
  265.  
  266.       end; { IndexFound }
  267.  
  268.    { ----- HoleFound ---------------------------------------------- }
  269.  
  270.    function TBase.HoleFound (S: Longint; var Pos: Longint): Boolean;
  271.  
  272.    { Looks for a hole in a storage stream.
  273.      Linear search, FIRST-FIT }
  274.  
  275.       var
  276.          Found : Boolean;
  277.          i     : Integer;
  278.  
  279.       begin
  280.  
  281.          with HolesIndex^ do
  282.               begin
  283.                  Found := False; i := 0;
  284.                  while not (Found or (i > Count-1)) do
  285.                        begin
  286.                           with IndRec(At(i)^) do
  287.                                if Size >= S
  288.                                   then begin
  289.                                           Found := True;
  290.                                           Pos := StartPos;
  291.                                           Size := Size - S;
  292.                                           if Size = 0
  293.                                              then AtDelete(i)
  294.                                        end; { if }
  295.                           i := i + 1
  296.                        end  { while }
  297.               end;  { with }
  298.          HoleFound := Found
  299.  
  300.       end; { HoleFound }
  301.  
  302.    { ----- Abort ---------------------------------------------- }
  303.  
  304.    procedure TBase.Abort;
  305.  
  306.    { Cancels transaction. Restores old DBIndex and HolesIndex }
  307.  
  308.       var
  309.          HoleStart,               { Start of probable hole }
  310.          Diff,                    { Length of probable hole }
  311.          IndLoc      : Longint;   { Old DBIndex location in stream }
  312.          i           : Integer;
  313.          NewRec      : PIndRec;   { Hole registration card }
  314.  
  315.       begin
  316.  
  317.          Dispose (DBIndex, Done);    { Destroying old indexes }
  318.          Dispose (HolesIndex, Done);
  319.          with BaseStream^ do
  320.               begin
  321.                  Seek (IndexPointerLocation); Read (IndLoc,4);
  322.                  Seek (IndLoc); DBIndex := PIndexCollection (Get)
  323.               end;
  324.          New (HolesIndex, Init(PIDLimit,Delta));
  325.          with DBIndex^ do
  326.               begin
  327.                  HoleStart := StorageStart;
  328.                  for i := 0 to Count-1 do
  329.                      begin
  330.                         Diff := IndRec(At(i)^).StartPos - HoleStart;
  331.                         if Diff > 0
  332.                            then begin
  333.                                    New (NewRec);
  334.                                    with NewRec^ do
  335.                                         begin
  336.                                            StartPos := HoleStart;
  337.                                            Size := Diff
  338.                                         end;
  339.                                    HolesIndex^.Insert(NewRec)
  340.                                 end;  { if }
  341.                         HoleStart := IndRec(At(i)^).StartPos +
  342.                                         IndRec(At(i)^).Size
  343.                      end;  { for }
  344.                  BaseStream^.Seek (HoleStart); BaseStream^.Truncate
  345.               end;  { with }
  346.          IndexSort (DBIndex, False);
  347.          IndexSort (HolesIndex, True);
  348.          PIDCurrent := IndRec(DBIndex^.At(DBIndex^.Count-1)^).ID + 1
  349.  
  350.       end;  { Abort }
  351.  
  352.    { ----- Commit ---------------------------------------------- }
  353.  
  354.    procedure TBase.Commit;
  355.  
  356.    { Acknowledges transaction by putting DBIndex into the stream }
  357.  
  358.       var
  359.          S,                      { Size of DBIndex }
  360.          IndLoc     : Longint;   { Index location in stream }
  361.          i, BasePos : Integer;   { Auxiliary variables }
  362.  
  363.       begin
  364.  
  365.          with DBIndex^ do
  366.               begin
  367.  
  368.                  for i := 0 to Count-1 do
  369.                      begin
  370.                         BasePos := IndRec(At(i)^).Base;
  371.                         if (BasePos <> -1) and (BasePos <> i)
  372.                            then begin
  373.                                    IndRec(At(i)^).Size :=
  374.                                          IndRec(At(BasePos)^).Size;
  375.                                    IndRec(At(i)^).StartPos :=
  376.                                          IndRec(At(BasePos)^).StartPos;
  377.                                    IndRec(At(i)^).Base := i;
  378.                                    IndRec(At(BasePos)^).Base := -1
  379.                                 end
  380.                      end;  { for }
  381.  
  382.                  i := 0;
  383.                  while ( i < Count ) do
  384.                        if IndRec(At(i)^).Base = -1
  385.                           then AtDelete (i)
  386.                           else i := i + 1;
  387.  
  388.                  for i := 0 to Count-1 do
  389.                      IndRec(At(i)^).Base := i
  390.  
  391.               end;   { with }
  392.  
  393.          S := BytesInStream (DBIndex);
  394.          if not HoleFound (S, IndLoc)
  395.             then IndLoc := BaseStream^.GetSize;
  396.          with IndRec(DBIndex^.At(0)^) do
  397.               begin
  398.                  ID := 0;
  399.                  StartPos := IndLoc;
  400.                  Size := S;
  401.                  Base := 0
  402.               end;
  403.          IndexSort (DBIndex, True);
  404.          with BaseStream^ do
  405.               begin
  406.                  Seek (IndLoc); Put (DBIndex);
  407.                  Seek (IndexPointerLocation); Write (IndLoc,4)
  408.               end;
  409.          if not DoneFlag
  410.             then Abort
  411.  
  412.       end;  { Commit }
  413.  
  414.    { ----- Init ---------------------------------------------- }
  415.  
  416.    constructor TBase.Init (AStream: PDBStream);
  417.  
  418.    { Opens an existing database stream or creates a new one }
  419.  
  420.       var
  421.          Descr     : Longint;    { Stream descriptor }
  422.          IndexCard : PIndRec;    { DBIndex registration card }
  423.  
  424.       begin
  425.  
  426.          TObject.Init;
  427.          BaseStream := AStream;
  428.          New (NS, Init);
  429.          New (DBIndex, Init(PIDLimit,Delta));
  430.          New (HolesIndex, Init(PIDLimit,Delta));
  431.          DoneFlag := False;
  432.          with BaseStream^ do
  433.               begin
  434.                  Descr := 0;
  435.                  Seek (0);
  436.                  if GetSize > 3 then
  437.                     Read (Descr,4);
  438.                  if Descr = Hallmark
  439.                     then Abort
  440.                     else begin
  441.                             Descr := Hallmark;
  442.                             Seek (0); Truncate; Write (Descr,4);
  443.                             Seek (IndexPointerLocation); Write (Descr,4);
  444.                             New (IndexCard);
  445.                             With IndexCard^ do
  446.                                  begin
  447.                                     ID := 0;
  448.                                     StartPos := StorageStart;
  449.                                     Size := 0;
  450.                                     Base := 0
  451.                                  end;
  452.                             DBIndex^.AtInsert (0,IndexCard);
  453.                             Commit
  454.                          end
  455.               end  { with }
  456.  
  457.       end;  {  Init  }
  458.  
  459.    { ----- Done ---------------------------------------------- }
  460.  
  461.    destructor TBase.Done;
  462.  
  463.    { Done is done ! }
  464.  
  465.       begin
  466.          DoneFlag := True;
  467.          Commit;
  468.          Dispose (NS, Done);
  469.          Dispose (DBIndex, Done);
  470.          Dispose (HolesIndex, Done)
  471.       end;  { Done }
  472.  
  473.    { ----- Create ---------------------------------------------- }
  474.  
  475.    function TBase.Create : Word;
  476.  
  477.    { Generates unique identifier }
  478.  
  479.       begin
  480.          if PIDCurrent < PIDLimit
  481.             then begin
  482.                     Create := PIDCurrent;
  483.                     PIDCurrent := PIDCurrent + 1
  484.                  end
  485.             else Create := 0
  486.       end;  { Create }
  487.  
  488.    { ----- Destroy ---------------------------------------------- }
  489.  
  490.    procedure TBase.Destroy (PID: Word);
  491.  
  492.    { Marks object registration card in DBIndex as destroyed (Base = -1).
  493.      If object's base has existed in a stream, it becomes a hole.
  494.      Object doesn't vanish from a stream until transaction is over
  495.      (Commit or Done). }
  496.  
  497.       var
  498.          Pos,                     { Number of object's card in DBIndex }
  499.          HolePos,                 { Number of a potential hole }
  500.          BasePos     : Integer;
  501.          BaseStart,
  502.          BaseSize    : Longint;   { Charasteristics of object's base }
  503.          NewRec      : PIndRec;   { New hole }
  504.          i           : Integer;
  505.  
  506.       begin
  507.  
  508.          with DBIndex^ do
  509.            begin
  510.              if not IndexFound (DBIndex, PID, Pos, True)
  511.                 then Exit;
  512.              BasePos := IndRec(At(Pos)^).Base;
  513.              IndRec(At(Pos)^).Base := -1;
  514.              if (BasePos = -1) or (BasePos = Pos)
  515.                 then Exit;
  516.              if IndexFound (HolesIndex, IndRec(At(BasePos)^).StartPos,
  517.                             HolePos, False)
  518.                 then Halt (1);
  519.              BaseStart := IndRec(At(BasePos)^).StartPos;
  520.              BaseSize  := IndRec(At(BasePos)^).Size;
  521.              if HolePos < HolesIndex^.Count
  522.                 then if BaseStart + BasePos =
  523.                         IndRec(HolesIndex^.At(HolePos)^).StartPos
  524.                         then begin
  525.                                IndRec(HolesIndex^.At(HolePos)^).StartPos :=
  526.                                       BaseStart;
  527.                                IndRec(HolesIndex^.At(HolePos)^).Size :=
  528.                                       IndRec(HolesIndex^.At(HolePos)^).Size +
  529.                                       BaseSize;
  530.                                Exit
  531.                              end;
  532.              if BaseStart + BaseSize < BaseStream^.GetSize
  533.                 then begin
  534.                         New (NewRec);
  535.                         NewRec^.StartPos := BaseStart;
  536.                         NewRec^.Size := BaseSize;
  537.                         HolesIndex^.AtInsert (HolePos, NewRec)
  538.                      end
  539.                 else begin
  540.                         BaseStream^.Seek (BaseStart);
  541.                         BaseStream^.Truncate
  542.                      end;
  543.              AtDelete (BasePos);
  544.              for i := BasePos to Count-1 do
  545.                  if IndRec(At(i)^).Base <> -1
  546.                     then IndRec(At(i)^).Base := IndRec(At(i)^).Base-1
  547.            end  { with }
  548.  
  549.       end;  { Destroy }
  550.  
  551.    { ----- Put ---------------------------------------------- }
  552.  
  553.    procedure TBase.Put (PID: Word; P: PObject);
  554.  
  555.    { Puts an object into the database }
  556.  
  557.       var
  558.          StreamPos, S : Longint;   { Location and size of an object }
  559.          Pos,                      { Number of object registration card }
  560.          BasePos      : Integer;   { Number of object's base card }
  561.          NewRec       : PIndRec;   { Object registration card }
  562.  
  563.       begin
  564.  
  565.          if PID >= PIDLimit
  566.             then Exit;
  567.          with DBIndex^ do
  568.               if IndexFound (DBIndex, PID, Pos, True)
  569.                  then begin
  570.                          BasePos := IndRec(At(Pos)^).Base;
  571.                          if BasePos <> Pos
  572.                             then begin
  573.                                     if BasePos <> -1
  574.                                        then Exit;
  575.                                     PID := Create;
  576.                                     if IndexFound (DBIndex, PID,
  577.                                                    BasePos, True )
  578.                                        then Halt (1);
  579.                                     IndRec(At(Pos)^).Base := BasePos;
  580.                                     Pos := BasePos
  581.                                  end  { if }
  582.                       end;  { if }
  583.          S := BytesInStream (P);
  584.          if not HoleFound (S, StreamPos)
  585.             then StreamPos := BaseStream^.GetSize;
  586.          New (NewRec);
  587.          with NewRec^ do
  588.               begin
  589.                  ID := PID;
  590.                  StartPos := StreamPos;
  591.                  Size := S;
  592.                  Base := Pos
  593.               end;
  594.          DBIndex^.AtInsert (Pos, NewRec);
  595.          with BaseStream^ do
  596.               begin
  597.                  Seek (StreamPos); Put (P)
  598.               end
  599.  
  600.       end;  { Put }
  601.  
  602.    { ----- Get ---------------------------------------------- }
  603.  
  604.    function TBase.Get (PID: Word): PObject;
  605.  
  606.    { Gets an object from the database }
  607.  
  608.       var
  609.          Pos,                { Number of object registration card }
  610.          BasePos : Integer;  { Number of object's base card }
  611.  
  612.       begin
  613.          Get := Nil;
  614.          if IndexFound (DBIndex, PID, Pos, True)
  615.             then begin
  616.                     BasePos := IndRec(DBIndex^.At(Pos)^).Base;
  617.                     if BasePos <> -1
  618.                        then begin
  619.                                BaseStream^.Seek
  620.                                    (IndRec(DBIndex^.At(BasePos)^).StartPos);
  621.                                Get := BaseStream^.Get
  622.                             end  { if }
  623.                  end  { if }
  624.       end;  { Get }
  625.  
  626.    { ----- ObjSize ---------------------------------------------- }
  627.  
  628.    function TBase.ObjSize (PID: Word): Longint;
  629.  
  630.    { Returns the size of an object }
  631.  
  632.       var
  633.          Pos,                { Number of object registration card }
  634.          BasePos : Integer;  { Number of object's base card }
  635.  
  636.       begin
  637.          ObjSize := 0;
  638.          if IndexFound (DBIndex, PID, Pos, True)
  639.             then begin
  640.                     BasePos := IndRec(DBIndex^.At(Pos)^).Base;
  641.                     if BasePos <> -1
  642.                        then ObjSize := IndRec(DBIndex^.At(BasePos)^).Size
  643.                  end  { if }
  644.       end;  { ObjSize }
  645.  
  646.    { ----- Count ---------------------------------------------- }
  647.  
  648.    function TBase.Count: Integer;
  649.  
  650.    { Returns the number of objects in the database }
  651.  
  652.       begin
  653.          Count := DBIndex^.Count
  654.       end;  { Count }
  655.  
  656.    { ----- IdlePack ---------------------------------------------- }
  657.  
  658.    procedure TBase.IdlePack;
  659.  
  660.    { Makes a single step of database packing.
  661.      Method (just now) - simple sequential relocation.
  662.      Before object is relocated, old index is gotten
  663.      from the stream and then put back with proper amendments. }
  664.  
  665.       var
  666.           P         : PObject;           { Relocated object }
  667.           OldLoc,                        { Old location of relocated object }
  668.           NewLoc,                        { New location of relocated object }
  669.           IndLoc    : Longint;           { Location of old DBIndex }
  670.           OldIndex  : PIndexCollection;  { Old DBIndex }
  671.           Pos       : Integer;           { Posititon of relocated object
  672.                                            in the index }
  673.  
  674.       begin
  675.  
  676.          with HolesIndex^ do
  677.            with BaseStream^ do
  678.              begin
  679.  
  680.                if Count = 0
  681.                   then Exit;
  682.                OldLoc := IndRec(At(0)^).StartPos + IndRec(At(0)^).Size;
  683.                NewLoc := IndRec(At(0)^).StartPos;
  684.                Seek (OldLoc); P := Get;
  685.                if P = Nil
  686.                   then begin
  687.                           Reset;
  688.                           Seek (NewLoc); Truncate;
  689.                           AtDelete (0);
  690.                           Exit
  691.                        end;
  692.                Seek (IndexPointerLocation); Read (IndLoc,4);
  693.                Seek (IndLoc); OldIndex := PIndexCollection (Get);
  694.  
  695.                if IndexFound (OldIndex, OldLoc, Pos, False)
  696.                   then begin
  697.                           IndRec(OldIndex^.At(Pos)^).StartPos := NewLoc;
  698.                           if not IndexFound (DBIndex,
  699.                                              IndRec(OldIndex^.At(Pos)^).ID,
  700.                                              Pos, True)
  701.                              then Halt (1)
  702.                        end
  703.                   else begin
  704.                           Pos := 0;
  705.                           while (IndRec(DBIndex^.At(Pos)^).StartPos <>
  706.                                  OldLoc) do
  707.                                 Pos := Pos + 1
  708.                         end;
  709.                IndRec(DBIndex^.At(Pos)^).StartPos := NewLoc;
  710.  
  711.                if OldLoc = IndLoc
  712.                   then IndLoc := NewLoc;
  713.                Seek (NewLoc); Put (P);
  714.                Seek (IndexPointerLocation); Write (IndLoc,4);
  715.                Seek (IndLoc); Put (OldIndex);
  716.                Dispose (P,Done); Dispose (OldIndex, Done);
  717.  
  718.                IndRec(At(0)^).StartPos :=
  719.                       NewLoc + IndRec(DBIndex^.At(Pos)^).Size;
  720.                if Count > 1
  721.                   then if ( IndRec(At(0)^).StartPos + IndRec(At(0)^).Size =
  722.                             IndRec(At(1)^).StartPos )
  723.                           then begin
  724.                                  IndRec(At(0)^).Size :=
  725.                                  IndRec(At(0)^).Size + IndRec(At(1)^).Size;
  726.                                  AtDelete (1)
  727.                                end
  728.  
  729.              end  { With }
  730.       end;  { IdlePack }
  731.  
  732.     { -- End of TBase implementation -- }
  733.  
  734.    const
  735.       RIndexCollection: TStreamRec =
  736.          ( ObjType : 10000;
  737.            VMTLink : Ofs(TypeOf(TIndexCollection)^);
  738.            Load    : @TIndexCollection.Load;
  739.            Store   : @TIndexCollection.Store );
  740.  
  741. begin
  742.  
  743.   { Unit body }
  744.  
  745.   RegisterType (RIndexCollection)
  746.  
  747. end.