% adbookln.tu

unit
module  AddressBook
  export  Enter,   Delete,   Change,   LookUp, 
          PrintOut,   Load,   Save, 
          Initialize,    Finalize 

const fileName :=  "adbook.dat" 

type entry :
  record
    name, address : string
    next : ^entry
  end record

var first : ^entry

% Initialize address book to empty.  
procedure  Initialize() 
  first := nil
end Initialize

% Clear address book,
% freeing any space allocated for its elements
procedure  Finalize()  

  loop
    exit when first = nil
    var p: ^entry := first 
    first := p->next
    free p
  end loop

end Finalize     

% Return pointer to node containing name.
% If name not present, return nil.
% This function is used internally and is not exported.
function find (name : string) : ^entry

  % This is a sequential search.
  var where : ^entry := first

  loop
    exit when where = nil 
           or where -> name = name
    where := where -> next
  end loop

  result where

end find

% The name must not already be in the book.
% The success flag is set to true 
% if the addition was actually done;
% otherwise there was no more space.
procedure  Enter  (name, address : string,
                 var success : boolean)

  % Name must not be in book.
  pre find (name) = nil 
  var p : ^entry
  new p

  if p not= nil then % Space available?
    p -> name := name
    p -> address := address
    p -> next := first
    first := p
    success := true
  else
    success := false
  end if

end Enter

% Delete name with its address.
% The name must already be in the book.
procedure  Delete  (name : string)

  % Name must be in book.
  pre find (name) not= nil 
  var where : ^entry

  if first -> name = name then
    where := first
    first := where -> next
  else
    var prev : ^entry := first
    where := prev -> next

    loop
      exit when where -> name = name
      prev := where
      where := prev -> next
    end loop

    prev -> next := where -> next
  end if

  % We found the name.
  assert where -> name = name 
  free where

end Delete

% Change address for this name.
% The name must already be in the book.
procedure  Change   (name, address : string)

  const where := find (name)
  % Precondition: name must be in book.
  assert where not= nil 
  where -> address := address

end Change

% The success flag is set to true if the name
% was found, in which case the address is returned.
% Otherwise success is set to false.
procedure  LookUp   (name : string,
           var address : string,
  var success : boolean)
  const where := find (name)

  if where not= nil then
    address := where -> address
    success := true
  else
    success := false
  end if

end LookUp

% Print all names and addresses in book.
procedure  PrintOut() 
  var p : ^entry := first

  if p not= nil then
    loop
      put p -> name : 10, " ", p -> address
      p := p -> next
      exit when p = nil
    end loop
  else
    put "There are no entries in address book."
  end if

end PrintOut

% Read contents of book from a file.
procedure  Load() 
  first := nil % Book starts out empty.
  var fileNumber : int
  open : fileNumber, fileName, get

  if fileNumber not= 0 then % Did file exist?
    loop
      exit when eof (fileNumber)
      var p : ^entry
      new p
      % Assume space is available.
      assert p not= nil 
      get : fileNumber, p -> name : *,
            p -> address : *
      p -> next := first
      first := p
    end loop
    close : fileNumber
  end if

end Load

% Save contents of book in a file.
procedure  Save() 
  var fileNumber : int
  open : fileNumber, fileName, put
  var p := first

  loop
    exit when p = nil
    put : fileNumber, p -> name
    put : fileNumber, p -> address
    p := p -> next
  end loop

end Save
end AddressBook