-- File: StorageImpl.Mesa  Edited by
-- Smokey, 26-Jan-81 18:09:03
-- Karlton, Oct 8, 1980 1:37 PM
-- Forrest, July 25, 1980  7:06PM

DIRECTORY
  Environment USING [wordsPerPage],
  Heap USING [ExpandMDS, FreeMDSNode, GetAttributesMDS, MakeMDSNode, PruneMDS, systemMDSZone],
  Runtime USING [GetCaller],
  Space USING [
    Create, defaultBase, defaultWindow, Delete, GetHandle, Handle, Map, mds, 
    PageFromLongPointer, Pointer],
  Storage USING [];
  
StorageImpl: PROGRAM IMPORTS Runtime, Space, Heap EXPORTS Storage =
  BEGIN
  
  ownerChecking: BOOLEAN = Heap.GetAttributesMDS[Heap.systemMDSZone].ownerChecking;
  PageSize: CARDINAL = Environment.wordsPerPage;
  InvalidNode: PUBLIC ERROR [p: POINTER] = CODE;
  ZoneTooSmall: PUBLIC ERROR [p: POINTER] = CODE;
  
  Pages: PUBLIC PROCEDURE [npages: CARDINAL] RETURNS [base: POINTER] =
    BEGIN OPEN Space;
    space: Handle ← Create[npages, mds, defaultBase];
    Map[space, defaultWindow];
    RETURN[Pointer[space]];
    END;
    
  Words: PUBLIC PROCEDURE [nwords: CARDINAL] RETURNS [base: POINTER] =
    {RETURN[Pages[(nwords + PageSize - 1) / PageSize]]};
    
  FreePages, FreeWords: PUBLIC PROCEDURE [base: POINTER] =
    BEGIN OPEN Space;
    IF base # NIL THEN
      Delete[GetHandle[PageFromLongPointer[base]]];
    END;
    
-- management of the heap

  Node: PUBLIC PROCEDURE [nwords: CARDINAL] RETURNS [p: POINTER] =
    BEGIN
    p ← Heap.MakeMDSNode[n: nwords];
    IF ownerChecking THEN (p-1)↑ ← Runtime.GetCaller[];
    RETURN[p]
    END;
    
  Free: PUBLIC PROCEDURE [p: POINTER] = {IF p # NIL THEN Heap.FreeMDSNode[p: p]};
  
  LocalString: PROCEDURE [nchars: CARDINAL] RETURNS [s: STRING] =
    BEGIN
    s ← Heap.MakeMDSNode[n: (nchars+1)/2 + 2];
    s↑ ← [length: 0, maxlength: nchars, text:];
    RETURN
    END;
    
  String: PUBLIC PROCEDURE [nchars: CARDINAL] RETURNS [s: STRING] =
    BEGIN
    s ← LocalString[nchars];
    IF ownerChecking THEN LOOPHOLE[(s-1), POINTER]↑ ← Runtime.GetCaller[];
    RETURN
    END;
    
  CopyString: PUBLIC PROCEDURE [s: LONG STRING, longer: CARDINAL ← 0]
    RETURNS [newS: STRING] =
    BEGIN
    l: CARDINAL = (IF s = NIL THEN 0 ELSE s.length);
    IF s = NIL AND longer = 0 THEN RETURN[NIL];
    newS ← LocalString[l + longer];
    FOR i: CARDINAL IN [0..l) DO newS[i] ← s[i] ENDLOOP;
    newS.length ← l;
    IF ownerChecking THEN LOOPHOLE[(newS-1), POINTER]↑ ← Runtime.GetCaller[];
    END;
    
  ExpandString: PUBLIC PROCEDURE [s: POINTER TO STRING, longer: CARDINAL ← 0] =
    BEGIN
    newS: STRING ← CopyString[s↑, longer + (IF s↑ = NIL THEN 0 ELSE s.maxlength - s.length)];
    FreeString[s↑];
    s↑ ← newS;
    IF ownerChecking THEN LOOPHOLE[(newS-1), POINTER]↑ ← Runtime.GetCaller[];
    END;
    
  FreeString: PUBLIC PROCEDURE [s: STRING] = LOOPHOLE[Free];
  
  Prune: PUBLIC PROCEDURE RETURNS [BOOLEAN] = {
    Heap.PruneMDS[Heap.systemMDSZone]; RETURN[TRUE]};
    
  Expand: PUBLIC PROCEDURE [pages: CARDINAL] = {Heap.ExpandMDS[Heap.systemMDSZone, pages]};
  
  -- initialization code
  
END.