Contributor: MARK GAUTHIER            

Unit MgLinked;

interface

const

      { Error list. }
      Succes       = $00;
      Need_Mem     = $01;
      Point_To_Nil = $02;

type

  DoubleLstPtr = ^DoubleLst;
  DoubleLst    = record
                   Serial       : longint;
                   Size         : word;
                   Addresse     : pointer;
                   Next         : DoubleLstPtr;
                   Previous     : DoubleLstPtr;
                 end;


  PDoubleLst = ^ODoubleLst;
  ODoubleLst = object

    private
    LastCodeErr : word;          {-- Last error.         --}

    public
    TotalObj    : longint;       {-- Total obj allocate. --}
    CurentObj   : DoubleLstPtr;  {-- Curent obj number.  --}

    constructor Init(var Install:boolean; Serial:longint; Size:word;
Data:pointer);
    {-- Initialise all variables, new curent.    ---}

    destructor Done;

    {--- get and clear the last err. ---}
    function  LastError:word;

    {--- Seek to end and add an object.                            ---}
    procedure Add(Size:word; Data:pointer);

    {--- Change the size of data of a object. 0 = change curent.   ---}
    procedure ChangeSize(Serial:longint; NewSize : word);

    {--- Insert an object before the curent obj. 0 = insert curent pos ---}
    procedure Insert(Serial:longint; Size:word; Data:pointer);

    {--- Delete an object from the list.  0 = delete curent.       ---}
    procedure Delete(Serial:longint);

    {--- Pointe on next or end, etc.                               ---}
    procedure SeekFirst;
    procedure SeekLast;
    procedure SeekNext;
    procedure SeekPrevious;
    procedure SeekNum(Serial:longint);

    {--- Move data from obj to user buffer                          ---}
    {--- 0 = use curent object.                                     ---}
    function MoveObjToPtr(Serial:longint; p:pointer):word;

    {--- Move user buffer to obj data.  obj data take ObjSize bytes ---}
    {--- 0 = use curent object.                                     ---}
    function MovePtrToObj(Serial:longint; p:pointer):word;

  end;

implementation

(****************************************************************************)

 procedure move(Src,Dst:pointer; Size:word);assembler;
 asm
    lds si,Src
    les di,Dst
    mov cx,Size
    cld
    rep movsb
 end;


(****************************************************************************)

constructor ODoubleLst.Init(var Install:boolean; Serial:longint; Size:word;
Data:pointer);
{-- Initialise all variables, new curent.    ---}
begin
     Install := false;
     if Serial = 0 then exit;
     New(CurentObj);
     if CurentObj = nil then exit;
     GetMem(CurentObj^.Addresse, Size);
     if CurentObj^.Addresse = nil then
     begin
          LastCodeErr := Need_Mem;
          exit;
     end;

     CurentObj^.Next     := nil;
     CurentObj^.Previous := nil;
     CurentObj^.Size     := Size;
     CurentObj^.Serial   := Serial;
     move(Data, CurentObj^.Addresse, Size);

     TotalObj := 1;

     Install             := true;
     LastCodeErr         := Succes;
end;

(****************************************************************************)

destructor ODoubleLst.Done;
{-- Initialise all variables, new curent.    ---}
begin
     repeat delete(0);
     until (LastError <> Succes) or (TotalObj <= 0);
end;

(****************************************************************************)

function  ODoubleLst.LastError:word;
{--- get and clear the last err. ---}
begin
     LastError   := LastCodeErr;
     LastCodeErr := 0;
end;

(****************************************************************************)

procedure ODoubleLst.Add(Size:word; Data:pointer);
{--- Seek to end and add an object.                            ---}
begin
     repeat SeekNext until LastError <> Succes; { SeekEnd }

     New(CurentObj^.Next);
     if CurentObj^.Next = nil then
     begin
          LastCodeErr := Need_Mem;
          exit;
     end;

     GetMem(CurentObj^.Next^.Addresse, Size);
     if CurentObj^.Next^.Addresse = nil then
     begin
          LastCodeErr := Need_Mem;
          exit;
     end;

     CurentObj^.Next^.Size := Size;

     { Store information data. }
     move(Data, CurentObj^.Next^.Addresse, Size);

     { Increment the total number of reccords. }
     inc(TotalObj);

     CurentObj^.Next^.Next := nil;
     CurentObj^.Next^.Previous := CurentObj;

     LastCodeErr := Succes;
end;

(****************************************************************************)

procedure ODoubleLst.ChangeSize(Serial:longint; NewSize : word);
{--- Change the size of an object.                             ---}
var p:pointer;
begin
     getmem(p,NewSize);
     if p = nil then
     begin
          LastCodeErr := Need_mem;
          exit;
     end;
     SeekNum(Serial);
     move(CurentObj^.Addresse, p, NewSize);
     freemem(CurentObj^.Addresse, CurentObj^.Size);
     CurentObj^.Size := NewSize;
     CurentObj^.Addresse := p;
     LastCodeErr := Succes;
end;

(****************************************************************************)

procedure ODoubleLst.Insert(Serial:longint; Size:word; Data:pointer);
{--- Insert an object before the curent obj.                   ---}
Var n:DoubleLstPtr;
begin
     new(n);
     if n = nil then
     begin
          LastCodeErr := Need_mem;
          exit;
     end;
     SeekNum(Serial);
     getmem(n^.Addresse, Size);
     if n^.Addresse = nil then
     begin
          LastCodeErr := Need_mem;
          exit;
     end;

     n^.Size := Size;
     move(Data, n^.Addresse, Size);

     n^.Previous := CurentObj^.Previous;
     n^.Next     := CurentObj;

     CurentObj^.Previous^.Next := n;
     CurentObj^.Previous       := n;

     inc(TotalObj);
end;

(****************************************************************************)

procedure ODoubleLst.Delete(Serial:longint);
{--- Delete an object from the list.                           ---}
begin
     SeekNum(Serial);
     if CurentObj^.Addresse <> nil then
     begin
           FreeMem(CurentObj^.Addresse,CurentObj^.Size);
          CurentObj^.Addresse := nil;
     end;

     CurentObj^.Next^.Previous := CurentObj^.Previous;
     CurentObj^.Previous^.Next := CurentObj^.Next;

     if CurentObj <> nil then Dispose(CurentObj);
     CurentObj := CurentObj^.Previous;

     dec(TotalObj);
end;

(****************************************************************************)

procedure ODoubleLst.SeekLast;
begin
     repeat SeekNext until LastError <> Succes;
end;

(****************************************************************************)

procedure ODoubleLst.SeekFirst;
begin
     repeat SeekPrevious until LastError <> Succes;
end;

(****************************************************************************)

procedure ODoubleLst.SeekNext;
begin
     if CurentObj^.Next = nil then
     begin
          LastCodeErr := Point_To_Nil;
          exit;
     end;
     CurentObj := CurentObj^.Next;
     LastCodeErr := Succes;
end;

(****************************************************************************)

procedure ODoubleLst.SeekPrevious;
begin
     if CurentObj^.Previous = nil then
     begin
          LastCodeErr := Point_To_Nil;
          exit;
     end;
     CurentObj := CurentObj^.Previous;
     LastCodeErr := Succes;
end;

(****************************************************************************)

procedure ODoubleLst.SeekNum(Serial:longint);
begin
     if Serial = 0 then exit;
     SeekFirst;
     repeat

           SeekNext;

           if CurentObj^.Serial = Serial then
           begin
                LastCodeErr := Succes;
                break;
           end;

           if LastError <> Succes then
           begin
                LastCodeErr := Point_To_Nil;
                break;
           end
           else continue;

     until false;

end;

(****************************************************************************)

function ODoubleLst.MoveObjToPtr(Serial:longint; p:pointer):word;
{--- Move data from obj to user buffer                         ---}
begin
     SeekNum(Serial);
     if (CurentObj^.Addresse = nil) or (p = nil) then
     begin
          LastCodeErr := Point_To_Nil;
          exit;
     end;
     move(CurentObj^.Addresse, p, CurentObj^.Size);
     LastCodeErr := Succes;
     MoveObjToPtr := CurentObj^.Size;
end;


(****************************************************************************)

function ODoubleLst.MovePtrToObj(Serial:longint; p:pointer):word;
{--- Move user buffer to obj data.  obj data take ObjSize bytes ---}
begin
     SeekNum(Serial);
     if (CurentObj^.Addresse = nil) or (p = nil) then
     begin
          LastCodeErr := Point_To_Nil;
          exit;
     end;
     move(p, CurentObj^.Addresse, CurentObj^.Size);
     LastCodeErr := Succes;
     MovePtrToObj := CurentObj^.Size;
end;


end.