DataMuseum.dk

Presents historical artifacts from the history of:

Bogika Butler

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Bogika Butler

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download

⟦2a910836d⟧ TextFile

    Length: 91776 (0x16680)
    Types: TextFile
    Names: »OBJDIR.SA«

Derivation

└─⟦8fc713706⟧ Bits:30009789/_.ft.Ibm2.50007356.imd Mogens Pelles Zilog 80,000 / EOS projekt
    └─⟦this⟧ »OBJDIR.SA« 

TextFile

 
æ*****************************************************************
                        Copyright 1984 by
                        NCR Corporation
                        Dayton, Ohio  U.S.A.
                        All Rights Reserved
******************************************************************
                        EOS Software produced by:
                        NCR Systems Engineering - Copenhagen
                        Copenhagen
                        DENMARK
*****************************************************************å
 
æ  Ver. 0.29  å
æ$h=0å æ no heap space å
æ$L-å
  (*
                               S T U B
 
                             M O D U L E
 
 
                          (OBJECT DIRECTORY)
                        for EOS - Operating System.
 
A Stub Object serves as a directory of objects and pointers.
    The Stub either owns or manages the objects.
 
A Stub may load an Installation Module and create
    a Callable general object or a Library Module.
 
The objects and pointers of a Stub may be protected
    by utilizing the Security object.
 
During bootstrap the Stub is the first object called by
    the kernel's Boot Process. The Stub loads a configuration
    module and calls it, to take care of creating other
    objects and configurating then.
 
 
 
 
 
 
 
 
Copyright NCR Corp. 1982
 
 
Written:  August 1982
By:       Peter Mikkelsen, SE-Copenhagen.
 
Version id:  00/00
Last update:  82-08-09
 
 
*)
    (*$e*)
(*
 
OVERVIEW OF THE MODULE'S TEXT:                               PAGE
 
 
Export description                                              5
Import description                                             10
Stub constants and types                                       12
Global routines:
 
    Auxiliary routines:
 
      - Setforeign                                             16
      - RealError                                              17
      - GetNextRec                                             18
      - concatNames                                            19
      - getShortid                                             20
      - VerifyOperation                                        20.2
 
    Routines to handle bucket entries:
 
      - LockEntry                                              21
      - lookup                                                 22
      - OccupyFree                                             23
      - CleanUpEntry                                           24
 
    Search routines:
 
      - GetRefSimple                                           25
      - GetRefComplete                                         26
 
    Global version of Stub entry-routines:
 
      - GlobalInsertPtr                                        27
      - GlobalGetRef                                           29
      - GlobalDelete                                           31
 
    The central installation routine:
 
      - Install                                                32
 
OBJECT Stub                                                    56
 
    Local routines:
 
      - CheckNewName                                           57
      - CheckOldName                                           58
 
    Private routines:
 
      - AddBucket                                              59
 
    Entry routines:
 
      - Init                                                   60
      - UseAlloc                                               61
      - UseSecurity                                            61
      - Load                                                   62
      - Create                                                 63
      - CreateAccess                                           64
      - InsertPointer                                          66
      - NewStub                                                67
      - GetRef                                                 69
      - ReName                                                 70
      - Delete                                                 71
      - Abort                                                  72
      - AbortAll                                               73
      - GetStubName                                            74
      - InitScan                                               75
      - DeleteSubStub                                          76
 
 
OBJECT Scan                                                    77
 
    Entry routine:
 
      - GetInf                                                 77
 
    Installation description                                   78
 
 
*)
 
 
Object program STUB;
 
æ$l+å
æ ------------------ Include import descriptions of modules -------------å
 
æ$F=family.univ.id,l-å
æ$l+å
æ$F=family.knel.id,l-å
æ$l+å
æ$F=family.iosys.id,l-å
æ$l+å
æ$F=family.sched.id,l-å
æ$l+å
æ$F=family.alloc.id,l-å
æ$L+å
æ------------------ External test output procedures -------------------å
 
type
   txt = array Æ1..addrmaxÅ of char;
   txtptr = ^ ÆÅ txt;
 
 
procedure PrintText ( t: txtptr ); æexternalå forward;
procedure PrintStack( t: txtptr ); æexternalå forward;
procedure Printvar  ( t: txtptr; univ v: blockptr); æexternalå forward;
procedure setTstFlg ( flg: integer ); æexternalå forward;
function  getTstFlg: integer; æexternalå forward;
 
 
PROCEDURE check
  (res: resultType);
BEGIN
  if res.main<>ok then printVar('*** ObjDir Check ***   res=',res);
  IF res.main<>ok THEN exception(res);
END æ***check***å;
 
 
PROCEDURE StopCheck
  (res: resultType);
BEGIN
æ#b#PrintVar('*** ObjDir StopCheck ***   res=',res);#e#å
  IF res.main<>ok THEN exception(res);
END æ***StopCheck***å;
 
PROCEDURE NoCheck
  (res: resultType);
BEGIN
æ#b#printVar('*** ObjDir NoCheck ***   res=',res);#e#å
END æ***NoCheck***å;
 
 
æ---------------- ObjDir definition ---------------------------------å
 
æ$F=family.objdir.idå
 
 
æ------------------- Common Types ---------------------------å
 
type
  maxBufBlock = array Æ0..addrMaxÅ of byte;
  bufPtr = ^ ÆÅ maxBufBlock;
  bufferRef = ^^ÆÅ maxBufBlock;
 
  name16 = array Æ1..16Å of char;
  nameMax= array Æ1..99Å of char;
 
(* Installation Module types *)
 
TYPE
    headerprefix = RECORD  (* size = 56 bytes *)
        size: word;
        sizeofModule: long;
        kind: word;  (* 0 = programModule, 1 = libraryModule *)
        addressProgObjDescr: word;
 
        (* Export Descr *)
        objectName: name16;
        noEntryDescrs: word; (* = 0 *)
        noLocalObjDescrs: word; (* = 0 *)
 
        (* Import descr *)
        noImportedObjDescrs: word; (* = 0 *)
        noSymbLibDescrs: word; (* = 0 *)
 
        (* program Object Description *)
        addFirstLocDatSegmDescr: word;
        noLocPtrs: word;
        noTempPtrs: word;
        sizetempData: long;
        callStack: sizeType;
        entryAddress: long;
        noObjectRefs: word;
        noLocDatsegms: word;
    END;
 
    Objrefdescr = RECORD  (* size = 18 bytes *)
        name: name16;
        locPtrIndex: word;
    END;
 
    LocdatSegmDescr = RECORD  (* size = 28 bytes *)
        size: word;  (* of description *)
        name: name16;
        locPtrIndex: word;
        options: word;
        sizeOfSegm: long;
        noLoadSections: word;
    END;
 
    LdSctDescr = RECORD  (* size = 12 bytes *)
        relStartAddr: long;
        length: long;
        addOfContents: long;
    END;
 
    ModifDescr = RECORD  (* size = 12 bytes *)
        noFunctCodeRefs: word;  (* = 0 *)
        noImportedSymbRefs: word;  (* = 0 *)
 
 
        (* ReLocation  Information *)
        assumedLogicalStartAddr: long;
        relocatable: word;  (* 0 = no, 1 = yes *) (* = 0 *)
        noAddrModifs:  word;  (* = 0 *)
    end;
 
(* STUB CONSTANTS *)
 
CONST
    SubStubsIndex =  13 ; (* The pointer-number of "SubStubs" *)
 
    AllocName =        'allocate        ';
    SchedName =        'scheduler       ';
    IntName =          'intscheduler    ';
    ConfigName =   'initconfig      ';
 
    EgoObjName =       '*               ';
    EgoEnvName =       '**              ';
 
    RootName =         '/               ';
    ObjDirName =       'objdir          ';
 
    NULL =             '                ';
 
    BucketSize = 20;
 
    NoOfPrefixes = 10;
 
    ShortidLength = 16;
 
    Slash = '/';
 
    ObjDirOrg = 0; æ SE-CP å
    ObjDirSys = 5000;
 
    initUserSize   = 80000;
    initKernelSize =  8000;
 
    (* Aux error codes *)
 
    stringTooShort   = 1;
    nameError        = 2;
    nameMissing      = 3;
    nameTooLong      = 4;
    nameTooShort     = 5;
    deleteError      = 6;
    subDirDelete     = 7;
    bootSetEmpty     = 8;
    noBuckets        = 9;
    headerTooShort   = 10;
    headerKind       = 11;
    indexError       = 12;
    nameNotSubDir    = 13;
    notCallable      = 14;
 
    (*$e*)
(* STUB TYPES *)
 
TYPE
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
    Subjectidentification = fullid;
 
    SPerm =  (StubPermit,stubDelete,stubGetRef,
                     StubWrite,stubReName);
 
    StubPermissions = SET OF Sperm;
 
    FPerm =  (filePermit,fileRead,fileWrite,
                             fileExecute);
 
    Filepermissions = SET OF FPerm;
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
 
    StubLocRef = ^^Stublocals;
    BucketRef = ^^bucketlocals;
 
    StubData = RECORD  (* Stub *)
      StubName: name16;
      MotherIndex: integer; (* index of this Stub in "MotherBucket" *)
    END;
 
    InstallMode = (Creating,loading);
 
    ScanData = record
      lastI: integer;
      end;
 
    ScanLocals = RECORD
      code: ref;
      data: ^^ScanData;
      currBucket: BucketRef;
      MotherStub: StubLocRef;
    END;
    ScanLocRef = ^^ ScanLocals;
 
(* BUCKETS:
 
    The Stub keeps its name entries in "buckets". Each bucket
    contains a number of entries (together with associated
    pointers). The bucket size is determined at the Stub's
    creation time (the bucket size of the Root Stub is a
    constant: "RootsBucketSize").
 
    The buckets are storage segments, each with an envelope
    containing the pointers associated with the name entries.
    The buckets are organized in an owner set ("Buckets") of
    the Stub.
 
    When the buckets run full, the Stub will try to allocate
    a new one automatically.
 
    All the bucket entries of a Stub are protected against
    concurrently conflicts by the "DirGate". *)
 
TYPE
 
    BucketEntry = RECORD
      Name: name16;
      index: integer; (* index of itself! *)
      NoProtected: boolean;
      kind: Integer;
    END;
 
    BucketArray = array Æ1..BucketSizeÅ of BucketEntry;
 
    BucketLocals = RECORD
      Entries: ^^ BucketArray;
      Ptrs:  ARRAY Æ1..bucketsizeÅ OF Ref;
    END;
 
    StubLocals = RECORD
 
      code: ref;
 
      BootOwnerSet: ref;
      Allocate: ref;  (* Simple *)
      Scheduler: ref;  (* Simple *)
      Intscheduler: ref;  (* Simple *)
 
      FullSpace: ref; (* Segment mapping of entire physical
                        address space *)
 
      DefVirt: ref; (* simple *)
 
      Ego: ObjDirRefType; (* refObj *)
      EgoEnv: StubLocRef; (* refEnv *)
 
      BootProc: ref;
 
      (* The pointers above are kernel-defined *)
 
      BootPos: BufferRef; (* maintains a position within the BootOwnerSet.
                            Points to the next segment to be treated *)
 
      (* Pointers to represent the tree-structure of the Stubs *)
 
      RootStub: StubLocRef; (* refEnv *)
      MotherStub: StubLocRef; (* refEnv *)
      SubStubs:   StubLocRef; (* manager set of sub-stubs *)
      MotherBucket: BucketRef; (* refEnv to bucket in mother stub *)
 
      (* Pointers to hold the entries under the Stub *)
      LocalData: ^^StubData; (* Storage segment *)
      Created: ^^; (* manager set of Callable Modules *)
      Buckets: BucketRef; (* manager set of bucket envelopment *)
      BucketOwners: ^^; (* owner set of buckets *)
      newBucketOwner: ^^; (* temporary owner set of new  buckets *)
 
      DirGate: ^^Gate; (* Protects insertion and removal of
                            bucket entries *)
      ScanSet: ScanLocRef; (* manager set of Scan object *)
 
      (* Standard objects under the stub *)
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
 
        Security: ^^SecuritySys; (* refObj *)
        IdentObj: ^^Ident;
        SysMan: ^^SystemMan;
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
 
    END;  (* StubLocals *)
    (*$e*)
 
function MakeResult ( family, main, aux, argNo: Byte ): resultType;
  var r: resultType;
  begin
    r.family := family;
    r.main := main;
    r.auxCause := aux;
    r.argNo := argNo;
    r.orgNo := ObjDirOrg;
    r.orgSys := ObjDirSys;
 
    MakeResult := r;
  end;
 
function LastNonBlank ( s: fullId ): integer;
  var i: integer;
  begin
    i := 0;
    while (i < elements(s)) and (sÆi+1Å > ' ') do i := i + 1;
    LastNonBlank := i;
  end;
 
procedure CopyBytes ( univ source, dest: blockPtr );
  var i, max: integer;
  begin
    max := elements ( source );
    if max > elements ( dest ) then max := elements ( dest );
    for i := 1 to max do destÆiÅ := sourceÆiÅ;
  end;
 
procedure FillBytes ( univ b: Byte; univ dest: blockPtr );
  var i: integer;
  begin
    for i := 1 to elements ( dest ) do destÆiÅ := b;
  end;
 
function LegalChar ( c: char ): boolean;
  begin
    legalChar := (c > ' ') and not (c = slash);
  end;
 
function NameOk ( name: shortid ): boolean;
  var
    i: integer;
    ok: boolean;
  begin
    ok := true;
    for i := 1 to LastNonBlank( name ) do begin
      ok := ok and LegalChar( nameÆiÅ );
      with c = nameÆiÅ do
        if ('A'<=c) and (c<='Z') then
          c := chr(ord('a')-ord('A')+ord(c));
    end;
    NameOK := ok;
  end; æ NameOk å
 
PROCEDURE  concatNames  ( name1: fullid;
                          name2: fullid;
                          outname: fullid);
 
    (* returns, "name1" concatenanted with "name2". A slash is
       inserted between the names if required, i.e. if "name1"
       doesn't end with a slash, and "name2" doesn't login with
       a slash. The syntax of the names is not verified.
 
       Abnormal result:
 
         NameTooLong: "name1" and "name2" cannot fit into "outname".
 
    *)
 
    var i, length1, length2, lengthOut, lengthRest: integer;
        insertSlash: boolean;
 
BEGIN
æ#b#  PrintText ( ' ConCatNames ');#e#å
  length1 := LastNonBlank ( name1 );
  length2 := LastNonBlank ( name2 );
  lengthOut := elements ( outName );
  if (length1 = 0) or (length2 = 0) then
    Exception(MakeResult(Universal,-DataValueIllegal,stringTooShort,0));
  insertSlash := not ((name1Ælength1Å=slash) or (name2Æ1Å=slash));
  if insertSlash then i := 1 else i := 0;
  lengthRest := lengthOut-(length1+length2+i);
  if lengthRest >= 0 then begin
    CopyBytes(name1Æ1..length1Å, outName);
    if insertSlash then outNameÆlength1+1Å := slash;
    CopyBytes(name2Æ1..length2Å,
              outNameÆlength1+1+i..lengthOutÅ);
    if lengthRest > 0 then
      FillBytes(' ',
                outNameÆlength1+1+i+length2..lengthOutÅ);
  end else begin
    Exception(MakeResult(Universal,-DataValueIllegal,stringTooShort,-1));
  end;
æ#b#  Printvar ( ' ConcatNames  Newname = ' , outname );#e#å
END;  (*** concatNames ***)
    (*$e*)
PROCEDURE getShortid (VAR name: fullId;
                      VAR base: integer;
                      VAR firstShortid: name16);
 
    (* Scans "Name" for the first shortid after index "base"
       (i.e. NameÆbase+1..elements(name)Å is scanned).
       The "first shortid" is defined as follows:
 
         1: It may be prefixed by a slash.
         2: It is syntactically similar to a Pascal identifier
            of up to 16 characters.
         3: The end-delimiter must be a slash, blanks, or the
            physical end of "Name".
 
       At return "base" is updated to point to the last
       character of the shortid found, thus being "base" of
       the next shortid. *)
 
    VAR i, nameLast: integer;
        finish: boolean;
 
BEGIN
æ#b#  PrintText (' Getshortid ');#e#å
    nameLast := LastNonBlank( name );
    IF nameLast <= base THEN firstShortid := NULL
    ELSE BEGIN
      IF NameÆbase+1Å = slash THEN base := base+1;
 
      IF base = nameLast THEN
        Exception(MakeResult(Universal,-DataValueIllegal,nameMissing,-1));
      IF not LegalChar ( nameÆbase+1Å ) THEN
        Exception(MakeResult(Universal,-DataValueIllegal,nameError,-1));
 
        i := 1; finish := false;
        REPEAT
          IF LegalChar ( nameÆbase+1Å ) THEN BEGIN
            with c = nameÆbase+1Å do
            if ('A'<=c) and (c<='Z') then
              firstshortidÆiÅ := chr(ord('a')-ord('A')+ord(c))
            else
              firstshortidÆiÅ := c;
            base := base+1; i := i+1;
          END ELSE BEGIN
            finish := true;
            IF NOT (NameÆbase+1Å = slash) THEN
              Exception(MakeResult(Universal,-DataValueIllegal,nameError,-1));
          END;
        UNTIL (base=nameLast) OR finish or (i>ShortidLength);
        IF i > ShortIdLength THEN
          Exception(MakeResult(Universal,-DatavalueIllegal,nameTooLong,-1));
        IF i < ShortIdLength THEN
          FillBytes (' ',firstShortIdÆi..ShortIdLengthÅ);
  END;
æ#b#printVar('ShortId = ', firstShortId);#e#å
END;  (*** getShortid ***)
    (*$e*)
PROGRAM SCANIMPLEMENT OBJECT ITEMSCAN WITH SCANLOCALS;
 
    entry GetInf with record tt: ref; end;
           (* out Name: shortid;
              OUT kind: Integer *)
 
    VAR
      found: boolean;
      auxText: shortId;
    BEGIN
æ#b# PrintText (' GetInf '); #e#å
      WITH data^^ DO BEGIN
        Check(motherstub^^.DirGate.Lock);
        in
          found := false;
          while not found do begin
            WITH d = currBucket^^.Entries^^ DO BEGIN
              WHILE (lastI < bucketSize) AND NOT found DO BEGIN
                lastI := lastI+1;
                found :=(dÆlastIÅ.kind <> FreeEntry) AND
                        (dÆlastIÅ.kind <> LockedEntry);
              END;
              IF found THEN BEGIN
                FillBytes(' ',Name);
                CopyBytes(dÆlastIÅ.Name, Name);
                kind := dÆlastIÅ.kind;
 
                if NextValArg( auxText ) then begin
                  FillBytes(' ', auxText);
                  case kind of
         loadedProgram    :    CopyBytes('preloaded program',auxText);
         loadedLibrary    :    CopyBytes('library module',auxText);
         generalObject    :    CopyBytes('general object',auxText);
         accessObject     :    CopyBytes('access object',auxText);
         pointerItem      :    CopyBytes('pointer item',auxText);
         subDir           :    CopyBytes('local directory',auxText);
                  end;
                end; æifå
              END; æ IF found å
            END; æ WITH å
            if not found then begin
              StopCheck(NextInSet(MotherStub^^.Buckets,CurrBucket));
              lastI := 0;
            end;
          end; æ while not found å
        do æ nothing å;
 
        Check(MotherStub^^.DirGate.Open);
 
        if not found then
          ObjReturn(MakeResult(objDirFamily,-ExtRefNotFound,0,0));
      end; æ with data^^ å
 
    END;  (*** GetInf ***)
otherwise scanOther with record
  t1: ref;
  end;
begin
  Exception(MakeResult(Universal,entryIllegal,0,0) );
end;
 
END;  (***** Scan *****)
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
(* global *) FUNCTION VerifyOperation (permission: Stubpermissions;
                                       VAR targetStub: StubLocRef;
                                       Name: Shortid): boolean;
 
      (* Verifies that the caller of the Stub system has the
         permission "permission" for "Name" in "TargetStub" -
         or that "Name" isn't protected *)
 
    VAR SystemId: Subjectidentification;
        UserId: Subjectidentification;
        result: ResultType;
        fullName: fullid;
        protected: boolean;
        perms: Stubpermissions;
 
    BEGIN
     PrintText (' VerifyOperation ');
        VerifyOperation:= true;
        IF SameEntity(TargetStub^^.Security , VOID) THEN VerifyOperation:=true
        ELSE
        BEGIN
            VerifyOperation := false;
            Result := TargetStub^^.Allocate.GetId (1, SystemId,UserId);
            WITH d = TargetStub^^.LocalData^^ DO
                concatNames (result, d.StubName, Name, fullName);
            Result := TargetStub^^.Security.VerifyItem (systemId,
                                          UserId, perms,fullname);
 
            IF (Result.main = ok) AND
               (permission IN perms OR NOT protected) THEN
                VerifyOperations := true;
    END;
END;  (*** VerifyOperations ***)
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
    (*$e*)
  FUNCTION LookUpEntry  (VAR TargetStub: StubLocRef;
                         VAR Name: name16;
                         VAR Bucket: BucketRef;
                         VAR entryNo: BucketEntry): boolean;
 
      (* Search for "Name" in TargetStub". If an entry is found,
         it is locked, and the specifications: "Bucket" and
         "entry" are returned. If no entry is found, "LockEntry"
         returns "false". *)
 
    VAR
        found: boolean;
        i: integer;
 
  BEGIN
æ#b#   PrintText (' LookUpntry ');#e#å
    found := false;
    in
      StopCheck ( FirstInSet (TargetStub^^.Buckets ,bucket) );
 
          REPEAT
              WITH d = Bucket^^.Entries^^ DO
              BEGIN
                  i := 0;
                  REPEAT
                      i := i+1;
                      found := (dÆiÅ.Name = Name)
                                AND (dÆiÅ.kind <> FreeEntry)
                                AND (dÆiÅ.kind <> LockedEntry);
                  UNTIL found OR (i = bucketSize);
                  IF found THEN
                  BEGIN
                      entryNo := dÆiÅ;
                  END;
              END;
              IF NOT found THEN StopCheck ( NextInSet (TargetStub^^.Buckets,
                                                       bucket) );
          UNTIL found;
    do æ nothing å;
    LookUpEntry := found;
  END;  (*** LockEntry ***)
    (*$e*)
FUNCTION lookup  (VAR Targetstub: StubLocref;
                  Name: name16;
                  VAR Bucket: BucketRef;
                  VAR entryNo: BucketEntry;
                  VAR ObjRef: ref): boolean;
 
      (* Searches for "Name" in the specified Stub ("TargetStub")
         Returns the corresponding entry and pointer. The pointer
         (ObjRef") is a refObj, except when referring to a Stub
         in which case an envelope reference is returned. If a
         Loaded Module is referred to, a pointer to the first
         Storage segment of the owner set is returned in "ObjRef".
 
         If no entry is found, "lookup" returns false.
         The parameter "Bucket" returns an envelope reference
         to the bucket in which the entry was found. This reference
         is used to handle Loaded Modules (i.e. inspecting the
         owner set of such), only. *)
 
    BEGIN
æ#b#      PrintText (' Lookup ');#e#å
      Check ( TargetStub^^.DirGate.Lock );
      in
         IF LookUpEntry (TargetStub, Name, Bucket, entryNo) THEN
         BEGIN
 
             CASE entryNo.kind OF
 
 generalObject,loadedLibrary,accessObject,pointerItem,subDir  :
                 Check ( Copy ( Bucket^^.PtrsÆentryNo.indexÅ,ObjRef) );
 
                 loadedProgram:
                 Check ( FirstInSet (Bucket^^.PtrsÆentryNo.indexÅ,ObjRef) );
             END;
             lookup := true;
         END ELSE
             lookup := false;
         Check ( TargetStub^^.DirGate.open );
      do begin
        Check ( TargetStub^^.DirGate.open );
        Exception ( GetException );
      end;
    END;  (*** lookup ***)
    (*$e*)
FUNCTION OccupyFree  (VAR TargetStub: StubLocref;
                      VAR NewName: name16;
                      VAR Bucket: BucketRef;
                      VAR index: integer): boolean;
 
      (* Finds a free bucket entryNo in the indicated Stub, and
         marks it as "locked". "NewName" MAY be used to guide
         the selection of a free entryNo, thereby optimizing later
         searches for the name. The entryNo found is specified by
         "bucket" and "index" on return.
 
         If these is no room left for the new entryNo "OccupyFree"
         will try to allocate a new bucket, but if that fails,
         it will return "false" *)
 
    VAR
         found: boolean;
         size: SizeType;
         i: integer;
 
BEGIN
æ#b# PrintText (' OccupyFree ');#e#å
  Found := false;
 
  Check ( TargetStub^^.DirGate.Lock );
 
  in
    StopCheck ( FirstInSet (TargetStub^^.Buckets, Bucket) );
 
    REPEAT
      WITH d =  Bucket^^.Entries^^ DO BEGIN
        index := 1;
        WHILE (index < bucketSize) AND
              (dÆindexÅ.kind <> FreeEntry) DO index:=index+1;
 
        found := dÆindexÅ.kind = FreeEntry;
        IF found THEN dÆindexÅ.kind := LockedEntry;
      END;
      IF NOT found THEN StopCheck(NextInSet (TargetStub^^.Buckets, Bucket) );
    UNTIL found;
  do ænothingå ;
  Check ( TargetStub^^.DirGate.open );
 
  if not found then begin æ add new bucket å
    NoCheck(ClearSize ( size ));
    NoCheck(AddEnv ( size, refs ( bucketLocals ) ));
    NoCheck(AddEmbSeg ( size, bytes ( bucketArray ) ));
 
    in
      Check ( targetStub^^.allocate.NewObj ( out targetStub^^.newBucketOwner;
                                             size, i ) );
      Check ( targetStub^^.DirGate.Lock );
      in
        Check ( MoveOwn ( targetStub^^.newBucketOwner,
                          targetStub^^.bucketOwners ) );
        with targetStub^^ do
          Check ( DeclEnv ( bucketOwners, buckets, bucket,
                  refs(bucketLocals), 0, makeSize(0,0),
                  makeSize(-1,-1) )  );
        Check ( NewSeg ( bucket^^.entries, bytes(bucketArray) ) );
        with d = bucket^^.entries^^ do begin
          for i := 1 to bucketSize do with dÆiÅ do begin
            index := i;
            kind := freeEntry;
          end;
          index := 1;
          dÆ1Å.kind := lockedEntry;
        end;
        found := true;
      do æ nothing å;
      Check ( targetStub^^.dirGate.open );
    do æ nothing å;
  end;
 
  OccupyFree := found;
END;  (*** OccupyFree ***)
    (*$e*)
PROCEDURE CleanUpEntry  (VAR TargetStub: StubLocref;
                         VAR bucket: Bucketref;
                         index: integer;
                         kind: Integer);
 
      (* Frees an already locked entryNo and deletes its
         associated object(s) *)
    var
      res: resultType;
 
    BEGIN
æ#b#     PrintText (' CleanUpEntry ');#e#å
      in
        repeat
          res := ( Dealloc ( bucket^^.PtrsÆindexÅ,
                             bucket^^.PtrsÆindexÅ ) );
          StopCheck( res );
        until false;
      do æ nothing å;
      in
        Check ( Copy ( Void, bucket^^.PtrsÆindexÅ ) );
      do Exception ( res );
 
      Check ( TargetStub^^.DirGate.lock );
      WITH d = bucket^^.Entries^^ DO
        dÆindexÅ.kind := FreeEntry;
      Check ( TargetStub^^.DirGate.open );
END;  (*** CleanUpEntry ***)
    (*$e*)
PROCEDURE GetRefSimple  (VAR StartStub: StubLocref;
                         VAR Name: name16;
                         FullName: fullid;
                         VAR Bucket: Bucketref;
                         VAR entryNo: BucketEntry;
                         VAR ObjRef: ref
                         VAR stub: stubLocRef );
 
      (* Searches (algol-like in scope) upwards from "StartStub" for
         the simple shortid "Name", and returns the corresponding
         entryNo and pointer (in case of a substub: an envelope
         pointer, though). The parameter BucketRef returns an
         envelope pointer to the Bucket in which the entryNo were
         found (BucketRef is only used when handling the owner
         sets of Loaded Modules).
 
         The complete fullid of the entryNo is returned in "FullName".
      *)
 
 
    VAR
        found: boolean;
 
BEGIN
æ#b#  PrintText (' GetRefSimple ');#e#å
  Check ( Copy ( startStub, stub ) );
  repeat
    found := lookUp ( stub, name, bucket, entryNo, objRef );
    if not found then begin
      check ( copy ( stub^^.motherStub, stub ) );
    end;
  until found or SameEntity ( Void, stub );
 
  if found then begin
    with d = stub^^.localdata^^ do
      concatNames ( d.stubName, name, fullName );
  end else begin
    exception(MakeResult(objDirFamily,-ExtRefNotFound, 0, 0 ) );
  end;
 
END;  (*** GetRefSimple **)
PROCEDURE  GetRefComplete  (VAR RootStub: StubLocref;
                            VAR Name: fullid; (* complete *)
                            VAR used: integer;
                            VAR targetStub: stubLocRef;
                            VAR Bucket: Bucketref;
                            VAR entryNo: BucketEntry;
                            VAR ObjRef: ref);
 
    (* Scans a complete fullid and returns the corresponding
       entryNo and pointer (in case of a substub: an envelope
       pointer). The parameter BucketRef returns an
       envelope pointer to the Bucket in which the entryNo were
       found (BucketRef is only used when handling the owner
       sets of Loaded Modules). *)
 
    VAR base: integer;
        sid: name16;
        finish: boolean;
 
BEGIN
æ#b#  PrintText (' GetRefComplete ');#e#å
    Check( Copy (RootStub, targetStub) );
    finish := false;
    base := 0;
    REPEAT
        getShortid ( Name,base, sid);
 
        IF sid <> NULL THEN
        BEGIN
 
            IF lookup (targetStub, sid, bucket, entryNo, ObjRef) THEN
            BEGIN
                used := base;
                finish := entryNo.kind <> subDir;
                if not finish then
                  Check(Copy(ObjRef,TargetStub) );
            END else begin
              Exception(MakeResult(objDirFamily,-ExtRefNotFound, 0, 0 ) );
            end;
        END else
            finish := true;
    UNTIL  finish;
 
    END;  (*** GetRefComplete ***)
    (*$e*)
PROCEDURE GlobalInsertPtr (VAR TargetStub: StubLocref;
                           Name: name16;
                           VAR Ptr: ref;
                           NoProtect: boolean
                           var bucket: bucketRef );
 
    (* Inserts a simple pointer in "TargetStub") *)
 
    VAR
        index: integer;
        fullNewName: nameMax;
 
BEGIN
æ#b#  PrintText (' GlobalInsertPtr ');#e#å
    IF NOT OccupyFree (TargetStub, Name, bucket, index) THEN
      Exception( MakeResult( Universal,-NoResources,0,0) );
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
    (* Create a security item for the pointer *)
    IF NOT SameEntity(TargetStub^^.Security , VOID) OR NotProtected THEN
    BEGIN
 
        permission := ÆStubPermit,StubDelete,StubGetRef,StubReNameÅ;
        WITH d = TargetStub^^.LocalData^^ DO
            concatNames (Result, d.StubName, Name, fullNewName);
        IF Result.main <> ok THEN GOTO exit (* NameTooLong *);
 
        RESULT := TargetStub^^.Allocate.GetId(1,SystemId,UserId);
        IF Result.main <> ok THEN
        GOTO exitlabel;
 
        RESULT := TargetStub^^.Security.CreateItem (SystemId,UserId,
                                      permission,fullnewname);
        IF Result.main <> ok THEN
        GOTO exitlabel;
 
    END;
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
    (* initialization bucket entryNo and make it public *)
 
    Check ( Copy (Ptr, bucket^^.PtrsÆindexÅ) );
    WITH d = bucket^^.Entries^^ DO
    BEGIN
        WITH e = dÆindexÅ DO
        BEGIN
            FillBytes ( ' ',e.name );
            CopyBytes ( name, e.name );
            e.Index := index;
            e.NoProtect := NoProtect;
            Check ( TargetStub^^.DirGate.Lock );
            e.Kind := pointerItem;
            Check ( TargetStub^^.DirGate.open );
        END;
    END;
 
END;  (*** GlobalInsertPtr ***)
    (*$e*)
PROCEDURE GlobalGetRef (VAR ThisStub: StubLocref;
                        name: fullid; (* complete or simple *)
                        VAR used: integer;
                        VAR ObjectRef: ref; (* may be subsegment
                                              owner on return *)
                        VAR Kind: integer;
                        VAR refp: ref;
                        VAR bucket: bucketRef;
                        VAR workRef1: ref  );
 
    (* Returns a simple pointer to a Callable Module, an Access
       Object, or a SubStub; a copy of a SimplePtr; or a subsegment
       pointer to a Library Module. It is checked that the
       "RequesterSubjId" is GetRef-permitted to the entity, or
       that the entity is NoProtect.
    *)
 
VAR
    entryNo: BucketEntry;
    sid: name16;
    fullName: nameMax;
    protected: boolean;
    size: SizeType;
    i: integer;
 
BEGIN
æ#b# PrintText (' GlobalGetRef ');#e#å
 
  IF nameÆ1Å = slash THEN BEGIN
    GetRefComplete (ThisStub^^.RootStub,name,used,
                    workRef1,bucket,entryNo,refp);
 
  END ELSE BEGIN
    used := 0;
    getShortid ( name, used, sid);
    GetRefSimple (ThisStub, sid, fullName, bucket,
                  entryNo, refp, workRef1 );
  END;
 
æ#b#printVar ( 'Entry = ', entryNo );#e#å
 
    IF entryNo.kind = loadedProgram THEN
      Exception(MakeResult(objDirFamily,-ExtRefProtected,0,0) );
 
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
    permission := ÆÅ;
 
    IF NOT entryNo.NoProtected THEN
    IF SameEntity(ThisStub^^.Security , VOID) THEN
        permission := ÆStubGetRefÅ
    ELSE
 
        RESULT := ThisStub^^.Security.VerifyItem (SystemId,UserId,permissions,
                                            fullname);
 
 
 
 
    IF NoProtected OR (stubGetRef IN permission) THEN
    BEGIN
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
        Kind := entryNo.kind;
 
        CASE kind OF
          generalObject, accessObject, pointerItem  :
              Check( Copy (refp, ObjectRef) );
          subDir :
              Check( Copy (refp:stubLocRef^^.Ego, ObjectRef) );
          loadedLibrary :
              BEGIN (* create subsegment with "execute" capability only *)
                  NoCheck( ClearSize (size));
                  NoCheck( AddSub (size));
 
                  Check ( ThisStub^^.Allocate.NewObj(out ObjectRef;
                          size, i ) );
                  Check ( DeclSub (ObjectRef, var program refp:bufferRef^^) );
              END;      æ!!!!!!!!!! pot. kernel problem !^^^^^^^^^^^^^^^ å
        END; (*case*)
 
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
        END ELSE
            SetResult (Result, Rejected, ExtRefProtected,
                objDirFamily, 0, refp);
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
 
    END;  (*** GlobalGetRef ***)
    (*$e*)
PROCEDURE GlobalDelete  (VAR TargetStub: StubLocref;
                         Name: name16;
                         VAR bucket: bucketRef );
 
    (* Deletes a bucket entryNo (not SubStub) in "TargetStub" *)
 
    VAR
        entryNo: BucketEntry;
BEGIN
æ#b# PrintText (' GlobalDelete ');#e#å
  Check( targetStub^^.Dirgate.Lock );
  in
    IF LookUpEntry (TargetStub, Name, bucket, entryNo) THEN BEGIN
 
        IF entryNo.kind = subDir THEN
          Exception(MakeResult(Universal,-EntryIllegal,SubDirDelete,0) );
        with d = bucket^^.entries^^ do
          dÆentryNo.indexÅ.kind := lockedEntry;
        Check( targetStub^^.DirGate.open  );
        in
          CleanUpEntry (TargetStub,bucket,entryNo.index,entryNo.kind);
        do begin
          Check ( targetStub^^.DirGate.Lock );
          Exception ( GetException );
        end;
    END ELSE BEGIN
        Exception(MakeResult(objDirFamily,-ExtRefNotFound, 0,0) );
    END;
  do begin
    Check ( targetStub^^.DirGate.open );
    Exception ( GetException );
  end;
 
END;  (*** GlobalDelete ***)
    (*$e*)
æ----------------------- Install ---------------------------å
type
  refArray = array Æ1..wordMaxÅ of ref;
 
  installTemps = record
    workRef1, workRef2,workRef3: ref;
    segm: bufferRef;
    bucket, targetBucket, loadBucket: bucketRef;
    loadPos: bufferRef;
    env: ^^refArray;
    auxBootPos: ref;
    faoObj: faoRefType;
    refHeader: bufferRef;
    rootStub: stubLocRef;
    end;
 
PROCEDURE Install
             (VAR ThisStub: StubLocref;
              callMode: InstallMode;
              VAR Name: name16;
              SourceName: fullid;
              SourceAddr: Address;
              NewSubject: boolean;
              NoProtect: boolean;
              VAR Obj: ref;
              VAR temps: installTemps);
 
    (* Creates or loads (depending on "callMode") an Installation
       Module.
 
       OVERVIEW OF PROCEDURE:
 
       Introduction: Various preparations
 
       1. Decide the exact source of the Installation Module and
          get caller's security item for that.
 
       2. Get the (subject) id, authorizing the creation of a new
          subject identification.
 
       3. Get the first part of the Installation Module Header.
 
       4. Find free bucket entryNo.
 
       5. Depending on callMode:
            creating: 5c.1: Compute size of general object
                      5c.2: Create general object
                      5c.3: Insert subject identification
                      5c.4: Initialize local pointers
 
            loading:  5l:   Create and initialize Header Segment
                            (if not Library Module).
 
       6. Create and initialize local data segments
 
       7. Create security item. Make entryNo public. Verify the return
            of a pointer in "Obj".
 
       ExitPart: Clean-up after errors, i.e. reestablish the
          situation as it were prior to the call of Install.
 
    *)
 
 
(* CONSTANTS *)
const
      programModule = 0; libraryModule = 1;
        (* value of "kind"-field in Installation Module Header *)
      reentrant = 1;
 
(* TEMPORARY VARIABLES *)
 
    (* auxiliary.
       (no information is carried from one part to the next in
        any of these variables) *)
 
VAR     entryNokind: Integer;
        used,
        pos,
        auxpos,
        i, j: integer;
        sBeg, sEnd: integer;
        size: SizeType;
        sid: name16;
        entryNo: BucketEntry;
        sourceProtected: boolean;
        res: resultType;
 
    (* variables used to specify the exact source and its
       attributes= *)
 
       loadMode: (fromFile,fromLoaded,fromBoot,fromROM);
       LocalName: nameMax;
       nameLength: integer;
           (* CASE localMode OF
               fromFile: complete LocalName of file
               fromLoaded: complete name of Loaded Module
               otherwise irrelevant *)
 
    (* following variables are relevant only for loadMode = fromFile *)
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
        FSSystemId: fullid;
            (* complete name of file system in which the source
               originates, concatenated with the security class of
               the file system: <filesys name>/<class> *)
        filePerms: Fpermissions;
            (* caller's security item for the load file *)
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
 
    (* following variables are relevant only for loadMode = fromLoaded *)
        loadEntry: BucketEntry; (* entryNo of Loaded Module *)
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
        loadPerms: StubPermissions;
            (* caller's security item for the Loaded Module *)
 
    (* Other Security variables *)
 
       SystemId,
       AuthorizingId: SubjectIdentification;
 
       permissions: StubPermissions;
           (* the creator's security item for the new object *)
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
    (* variables used to specify the target entryNo *)
 
       TargetIndex: integer;  (* index in "TargetBucket" *)
       fullObjName: nameMax;
           (* complete name of new entryNo *)
 
    (* variables used to hold Header Segment or parts hereof during
         load *)
 
const
       blockLength = 256;
var
       firstHBlock: record
         size: word;
         rest: array Æ3..blocklengthÅ of byte;
         end;
       headerPos: integer;
           (* the last byte retrieved from the refHeader^^-array *)
 
       (* following records reflect the static portions of the
          Installation Module format: *)
 
           HPrefix: HeaderPrefix;
           loadSectDescr: LdSctDescr;
           locSegmDescr: LocDatSegmDescr;
           modificationDescr: ModifDescr;
           objectRefDescr: ObjRefDescr;
 
  procedure GetNextRec ( var pos: integer; univ rec: bufPtr );
    begin with temps do begin
      with d = refHeader^^ do begin
        copyBytes(dÆpos..elements(d)-1Å, rec);
æ#b#        PrintVar (' GetNextRec   Rec: ', rec );#e#å
        pos := pos + elements(rec);
        if pos > elements(d) then
         Exception(MakeResult(objDirFamily,
                              -HeaderFormatError,headerTooShort,0));
      end;
    end; æ with temps å
    end; æ GetNextRec å
 
  procedure CheckIndex ( i: integer );
    begin
      if (i<1) or (i>hPrefix.NoLocPtrs) then
        Exception(MakeResult(objDirFamily,HeaderFormatError,indexError,0));
    end;
 
    (* Install, Introduction *)
 
    (* Various preparations *)
BEGIN with temps do begin
 
       Check ( Copy (ThisStub^^.RootStub,RootStub) ); (* often used *)
 
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
       IF callMode = loading THEN  BEGIN
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
           NewSubject := false; (* just to be sure *)
          NoProtect := true; (* just to be sure *)
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
       END;
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
 
æ#b#PrintText (' Install part 1 ');#e#å
(* Install, part 1 *)
 
(* Decide the exact source of the Installation Module and get
   caller's security item for it *)
 
fillBytes(' ', localName);
nameLength := LastNonBlank(sourceName);
IF nameLength <> 0 THEN
BEGIN
æ#b# PrintVar (' SourceName ', sourceNameÆ1..nameLengthÅ );#e#å
  in
    used := 0;
    IF SourceNameÆ1Å = slash THEN BEGIN
      GetRefComplete (ThisStub^^.RootStub,SourceName,used,
                      workRef1,loadBucket,loadEntry,loadPos);
    END ELSE BEGIN
      getShortid (SourceName,used,sid);
      GetRefSimple (ThisStub,sid,LocalName,
                    loadBucket,loadEntry,loadPos,workRef1 );
    END;  (* simple name *)
  do begin
    res := getException;
    if (res.orgSys=ObjDirSys) and
       (res.orgNo =ObjDirOrg) then
      res.argNo := -2;
    Exception ( res );
  end;
  IF used < nameLength THEN BEGIN
    (* must be a file *)
æ#b#       PrintText (' Source is a file ');#e#å
    if loadEntry.kind in ÆloadedProgram, loadedLibrary, subDirÅ then
      Exception(MakeResult(objDirFamily,-SourceNotFound,notCallable,-2));
    if sourceNameÆused+1Å = slash then used := used + 1;
    StopCheck (loadPos.ASSIGN (out faoObj;SourceNameÆused+1..nameLengthÅ,
               readRight, OldFile ) );
    loadMode := fromFile;
    CopyBytes(SourceNameÆused+1..nameLengthÅ,localName);
  END ELSE BEGIN
    (* must be a Loaded Module *)
æ#b#       PrintText (' source is a loaded module ');#e#å
    loadMode := fromLoaded;
    IF (loadEntry.kind <> loadedProgram) OR (callMode = loading) THEN
        Exception(MakeResult(objDirFamily,-SourceNotFound,0,-2) );
    CopyBytes (SourceName, localName);
  END;
 
END ELSE BEGIN
      (* SourceName = NULL *)
æ#b# PrintText (' source is empty ');#e#å
 
    IF SourceAddr = 0 THEN loadMode := fromBoot
                      ELSE loadMode := fromROM;
 
END;
 
(* Now "loadMode" specifies the type of source, and depending on
   that, the following variables specify the exact source:
 
    fromFile: "faoObj"
    fromLoaded: "loadBucket","loadEntry","loadPos"
    fromBoot: given by root stub's local pointers ("BootOwnerSet" and
              "BootPos")
    fromROM:  ?
 
    "LocalName" specifies either the complete LocalName of the
    load FILE or the complete (stub-) name of the LOADED Module *)
 
 
(* Get the caller's security item for the source. If "NoProtect"
   is specified by the caller, check if it is legal *)
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
 
IF NOT SameEntity(ThisStub^^.Security , VOID) THEN
BEGIN
 
    Result := ThisStub^^.Allocate.GetId (1,SystemId,UserId);
    IF Result.main <> ok THEN GOTO foreignexit;
 
    CASE loadMode OF
      fromFile:
        BEGIN
 
          (* Get file system's SystemId *)
          Result := ThisStub^^.Allocate.GetObjIdent (faoObj,subjectId);
          IF Result.main <> ok THEN GOTO foreignexit;
          FSSystemId := subjectId.SystemId;
 
          Result := ThisStub^^.Security.VerifyItem (SystemId,UserId,
                                                filePerms,
                                                localname);
          IF Result.main <> ok THEN GOTO foreignexit;
        END;
      fromLoaded:
        BEGIN
            IF loadEntry.NoProtect THEN sourceProtected := false
            ELSE
            BEGIN
              Result := ThisStub^^.Security.Verifyitem (SystemId,UserId,
                                                    loadPerms,
                                                    localname);
              IF Result.main <> ok THEN GOTO foreignexit;
            END;
    fromBoot,
    fromROM:
 
            sourceProtected := false
 
  END; (* case *)
 
 
    (* Check the validity of "NoProtect" *)
 
    IF NoProtect AND sourceProtected THEN
    BEGIN
 
        SetResult (Result, Rejected, ExtRefProtected, objDirFamily,0
                   LoadMode);
        GOTO exitlabel;
    END;
  END;
 
(* "filePerms" or "loadPerms" are now defined (if "NoProtect" isn't set)
   "CallersSubjtId" is defined
   "FSSystemId" is defined if loadMode = fromFile *)
(* INSTALL, PART 2 *)
 
(* Get the id authorizing the creation of a new object
   identification (only "NewSubject" is set)
 
   The id consists of the following:
   fromfile: (FSSystemid/LocalName, caller's userid, caller's termid);
   fromLoaded: (LocalName         ,     --"--      ,     --"--      );
   fromBoot:   (NULL              ,     --"--      ,     --"--      );
   fromROM:                       ,     --"--      ,     --"--      );
*)
 
if NewSubject AND (NOT RefEqal(ThisStub^^.Security, void)) THEN
BEGIN
 
    AuthorizingId := SystemId;
 
    CASE loadMode OF
      fromFile:
          concatNames (Result,FSSystemId,LocalName,
                       AuthorizingId.SystemId);
 
      fromLoaded:
          AuthorizingId.SystemId := LocalName;
 
      fromBoot,
      fromROM: AuthorizingId.SystemId := NULL;
 
    END;  (* case *)
END;
 
(* Now "AuthorizingId" is defined "NewSubject" is set *)
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
    (*$e*)
(* INSTALL, PART 3 *)
æ#b#PrintText (' install part 3 ');#e#å
 
(* Get the first of the Installation Module Header
   (the "Header Prefix")  *)
 
CASE loadMode OF
 
  fromFile:
    BEGIN
æ#b#     PrintText (' loadmode = fromfile ');#e#å
      Check( faoObj.ReadSeq(var in out firstHBlock; out used ) );
      Check( NewSeg(refHeader, firstHBlock.size) );
      with h = refHeader^^ do begin
        copyBytes(firstHblock, h);
        if firstHblock.size > used then begin
          Check(faoObj.ReadSeq(var in out hÆused..firstHBlock.size-1Å;
                               out used ) );
        end;
      end;
    END;
fromLoaded:
  BEGIN
      (* Note: The indivisibility of the following on the Loaded
               Module's owner set is implicity ensured by the
               simple pointer "loadPos", i.e. if the Loaded
               Module is deleted during the operations, "loadPos"
               will go NIL (VOID), and the result-code
               "SourcePreempted" is generated *)
 
æ#b#         PrintText (' loadmode = fromloaded ');#e#å
         Check( Copy (loadPos, refHeader) );
         Check( NextInSet (loadBucket^^.PtrsÆloadEntry.IndexÅ,loadpos) );
    END;
 
  fromBoot:
    BEGIN
æ#b#        PrintText (' loadmode = fromboot ');#e#å
      if SameEntity (RootStub^^.BootPos, Void) then
        Exception(MakeResult(objDirFamily,-SourceNotFound,BootSetEmpty,0));
      in
        StopCheck( Copy (RootStub^^.BootPos, refHeader) );
        StopCheck( NextInSet(RootStub^^.BootOwnerSet,RootStub^^.BootPos) );
      do Exception(MakeResult(objDirFamily,-SourceNotFound,BootSetEmpty,0));
    END;
 
(* fromROM:
        not implemented *)
 
END;  (* case *)
 
headerPos := 0;
GetNextRec ( headerPos, hPrefix );
 
IF (hPrefix.kind = libraryModule) AND (callMode = creating) THEN
  Exception(MakeResult(objDirFamily,-HeaderFormatError,HeaderKind, 0) );
 
IF Name = NULL THEN Name := hPrefix.objectname; (* default *)
if not nameOk(name) then
  Exception(MakeResult(objDirFamily,-HeaderFormatError,NameError, 0));
IF lookup (ThisStub,Name,bucket,entryNo,bucket (* dummy *)) THEN
  Exception(MakeResult(objDirFamily,-ObjectNameExists, 0, 0) );
 
WITH d = ThisStub^^.LocalData^^ DO
    concatNames ( d.StubName, Name, fullObjName);
 
(* Now "hPrefix" contains the first "record" of the header.
   "refHeader" points to a storage segment containing the header,
   and "headerpos" specifies the last byte of the header prefix
   (i.e. it is base for the next "record").
 
   "Name" is defined and contains the new local name of the module
   we are producing. "fullObjName" is the corresponding complete
   name *)
 
 
    (*$e*)
(* INSTALL, PART 4 *)
 
(* Find free bucket entryNo in this Stub, and mark it as "locked"
   until further *)
æ#b#PrintText (' Install part 4 ');#e#å
 
IF NOT OccupyFree (ThisStub, Name, TargetBucket, TargetIndex) THEN
  Exception(MakeResult(Universal,-NoResources, NoBuckets,0) );
 
WITH d = TargetBucket^^.Entries^^, e = d ÆTargetIndexÅ DO
BEGIN
 
    e.Name := Name;
    e.Index := TargetIndex;
    e.NoProtect := NoProtect;
 
    (* e.kind is not touched: it is "LockedEntry" until
-      further *)
 
END;
 
 
    (*$e*)
in æ the remaining part of install å
 
(* INSTALL, PART 5 *)
 
(* The action of this part depends on the callMode:
 
    CREATING:
    5c.1: Compute the size of the general object to be created.
    5c.2: Create the general object
    5c.3: Insert Subject Identification
    5c.4: Initialize local pointers.
 
    LOADING:
    5l: If not loading a Library Module, create and initialize
        the Header Segment of the future Loaded Module.
 
*)
 
CASE callMode OF
  creating:
      BEGIN
æ#b#        PrintText (' CallMode = Creating ');#e#å
 
          (*** 5c.1: Compute size of general object ***)
 
          NoCheck(ClearSize (size));
 
          (* Add the sizes of the local data segments *)
 
             pos := hPrefix.addFirstLocDatSegmDescr +
                    hPrefix.addressProgObjDescrs;
 
             FOR i := 1 TO hPrefix.noLocDatSegms DO
             BEGIN
                 auxpos := pos;
                 getNextRec (auxpos,locSegmDescr);
 
                 CASE loadMode OF
 
                   fromFile: NoCheck(AddEmbSeg(size,locSegmDescr.sizeOfSegm));
 
                   fromLoaded: IF locSegmDescr.Options <> Reentrant
                                 THEN
                             NoCheck(AddEmbSeg (size,locSegmDescr.sizeOfSegm))
                               ELSE
                             NoCheck(AddEmbSub (size));
 
                   fromBoot: (* current implementation:
                                the BootFormat must be expanded *)
                            IF locSegmDescr.noLoadSections = 0 THEN
                             (* This is a non-initialized data segment
                                which is not represented in the
                                Boot Owner Set *)
                             NoCheck(AddEmbSeg (size,locSegmDescr.sizeOfSegm));
 
               (* fromROM: not implemented *)
 
               END;  (* case *)
 
               pos := pos + locSegmDescr.size;
           END;  (* for *)
       (* Add the object and the envelope size *)
 
           NoCheck(AddGen (size,hPrefix.noLocPtrs));
æ#b#       PrintVar (' Size = ',size );#e#å
       (*** 5c.2: Create the general object ***)
 
       Check( ThisStub^^.Allocate.NewObj
             (TargetBucket^^.ptrs ÆTargetIndexÅ;size,OUT i) );
 
       Check( DeclGen (TargetBucket^^.PtrsÆTargetIndexÅ,
                ThisStub^^.Created,Env,hPrefix.noLocPtrs,0,
                makeSize(0,0),makeSize(-1,-1),
                hPrefix.noTempPtrs,
                hprefix.sizeTempData,0,
                hPrefix.entryAddress,
                hPrefix.callStack, true) );
 
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
      (*** 5c.3: Insert Subject Identification ***)
      IF NOT SameEntity(ThisStub^^.Security , VOID) THEN
        IF NewSubject THEN
        BEGIN
 
            (* Check that "AuthorizingId" may create a new
               subject with system name = "Name" *)
 
            Result := ThisStub^^.SystMan.VerifyItem ( Name,
                       OUT sid (* class *), AuthorizingId);
            IF Result.main <> ok THEN GOTO foreignexit;
 
            (* produce the new subject identification *)
 
               concatNames (Result,Name,sid,SubjectId.SystemId);
                  (* ignore Result *)
               SubjectId.UserId := NULL;
               SubjectId.TermId := NULL;
 
            (* Attach it to the general object *)
 
             Result:= ThisStub^^.IdentObj.SetSystemId (
                          TargetBucket^^.Ptrs ÆTargetIndexÅ,
                                   SubjectId.SystemId);
               IF result.main <> ok THEN GOTO foreignexit;
 
        END ELSE
        BEGIN
 
            WITH SubjectId DO
            BEGIN
                SystemId := NULL;
                UserId := NULL;
                TermId := NULL;
            END;
        END;
 
    (* Now "SubjectId" contains the verified subject identification
       of the new general object *)
 
 
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
        (*** 5c.4: Initialize local pointers ***)
 
        FOR i := 1 TO hPrefix.noObjectRefs DO
        BEGIN
 
            getNextRec (headerpos,objectRefDescr);
            CheckIndex(objectRefDescr.LocPtrIndex);
            if objectRefDescr.name = egoObjName then
              Check( Copy(targetBucket^^.PtrsÆtargetIndexÅ,
                          env^^ÆobjectRefDescr.locPtrIndexÅ ) )
            else if objectRefDescr.name = egoEnvName then
              Check( Copy(env, env^^ÆobjectRefDescr.locPtrIndexÅ ) )
            else begin
              GlobalGetRef (ThisStub,
                            objectRefDescr.Name,used,
                            env^^ÆobjectRefDescr.locPtrIndexÅ, entryNoKind,
                            workRef1,workRef2,workRef3 );
            end;
 
        END;
    END;  (*creating *)
 
loading:
 
    BEGIN
        (*** 5l: Create and initialize Header Segment if not
                 Library ***)
æ#b#        PrintText (' CallMode = Loading ');#e#å
 
        IF hPrefix.kind = programModule THEN
        BEGIN
 
            WITH t = TargetBucket^^.PtrsÆTargetIndexÅ DO
            BEGIN
                NoCheck(ClearSize(size));
                NoCheck(AddSeg(size, hPrefix.size));
                Check( ThisStub^^.Allocate.NewObj (out t;
                       size,OUT i ) );
                Check( DeclSeg ( t, hPrefix.size) );
 
                with d = t:bufferRef^^ do begin
                  pos := 0;
                  GetNextRec ( pos, d );
                end;
 
            END;
        END;
    END;  (* loading *)
END;  (* case *)
 
 
    (*$e*)
(* INSTALL, PART 6 *)
æ#b#PrintText (' Install part 6 ');#e#å
 
(* Create and initialize the local data segments *)
 
headerpos := hPrefix.addFirstLocDatSegmDescr +
             hPrefix.addressProgObjDescrs;
 
FOR i := 1 TO hPrefix.noLocDatSegms DO
BEGIN
 
    auxpos := headerpos;
 
    getNextRec (auxpos,locSegmdescr);
    CheckIndex(locSegmDescr.LocPtrIndex);
 
    (* create any storage segment necessary *)
 
    CASE callMode OF
 
      creating:
          BEGIN
æ#b#PrintText (' Create storage segment callmode = creating ');#e#å
            case loadMode of
              fromFile: begin
                 Check( NewSeg (Env^^ÆlocSegmDescr.locPtrIndexÅ,
                               locSegmDescr.sizeOfSegm) );
                 Check( Copy (Env^^ÆlocSegmDescr.locPtrIndexÅ, segm) );
                end;
              fromLoaded: begin
                if locSegmDescr.Options = reentrant then begin
                 Check( NewSub (Env^^ÆlocSegmDescr.locPtrIndexÅ,
                   var program loadPos^^Æ0..locSegmDescr.sizeOfSegm-1Å));
                 Check( Copy (Env^^ÆlocSegmDescr.locPtrIndexÅ, segm) );
                end else begin
                 Check( NewSeg (Env^^ÆlocSegmDescr.locPtrIndexÅ,
                               locSegmDescr.sizeOfSegm) );
                 Check( Copy (Env^^ÆlocSegmDescr.locPtrIndexÅ, segm) );
                end;
                end;
              fromBoot: begin
                if locSegmDescr.noLoadSections = 0 then begin
                 Check( NewSeg (Env^^ÆlocSegmDescr.locPtrIndexÅ,
                               locSegmDescr.sizeOfSegm) );
                 Check( Copy (Env^^ÆlocSegmDescr.locPtrIndexÅ, segm) );
                end;
                end;
            end; æ case å
         END;
 
 
    loading:
        BEGIN
 
æ#b#PrintText (' create storage segment callmode = loading ');#e#å
            IF locSegmDescr.noLoadSections > 0 THEN
            BEGIN
                NoCheck(ClearSize(size));
                NoCheck(AddSeg(size, locSegmDescr.sizeOfSegm));
                Check( ThisStub^^.Allocate.NewObj
                      (out TargetBucket^^.PtrsÆTargetIndexÅ;
                       Size, i ) );
                Check( DeclSeg (TargetBucket^^.PtrsÆTargetIndexÅ,
                             locSegmDescr.sizeOfSegm) );
                Check( Copy (TargetBucket^^.PtrsÆTargetIndexÅ,segm) );
            END;
        END;
END;  (* case callMode *)
 
(* initialize the segment *)
 
CASE loadMode OF
 
  fromFile:
    BEGIN
æ#b#PrintText (' LoadMode = FromFile ');#e#å
        FOR j := 1 TO locSegmDescr.noLoadSections DO
        BEGIN
 
            (* insert load section *)
 
            getNextRec (auxpos,loadSectDescr);
 
            (* assumptions for the current version:
               1. Load Sections are inserted aligned at block
                  boundaries i.e. relStartAddr MOD 256 = 0, and
                  length mod 256 = 0
 
               2. Load Sections are found aligned at block
                  boundaries in the Installation Module:
                  i.e. addrOfContents MOD 256 = 0. *)
            sBeg := loadSectDescr.relStartAddr;
            sEnd := loadSectDescr.relStartAddr+loadSectDescr.length-1;
            Check(faoObj.ReadSeq(var in out segm^^ÆsBeg..sEndÅ;
                                             OUT used) );
 
æ!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            Check(faoObj.ReadSeq(var in out segm^^ÆloadSectDescr.relStartAddr
                                           ..loadSectDescr.relStartAddr+
                                             loadSectDescr.length -1Å;
                                             OUT used) );
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!å
        END;
    END;  (* fromFile *)
 
    fromLoaded:
        BEGIN
æ#b#PrintText (' LoadMode = fromloaded ');#e#å
            IF NOT (locSegmDescr.noLoadSections = 0) THEN
            BEGIN
                IF NOT (locSegmDescr.Options = Reentrant) THEN
                  with s = segm^^, t = loadPos^^ do
                    CopyBytes ( t, s );
                NoCheck( NextInSet (loadBucket^^.PtrsÆloadEntry.indexÅ,
                                  loadpos) );
            END;
        END;  (* fromLoaded *)
 
 
    fromBoot:
      BEGIN
 
          CASE callMode OF
 
            creating: BEGIN
æ#b#PrintText (' loadmode = fromboot, callmode = creating ');#e#å
                IF locSegmDescr.noLoadSections > 0 THEN
                BEGIN  (* copy boot pointer *)
                 if SameEntity (RootStub^^.BootPos, Void) then
                        Exception(MakeResult(objDirFamily,
                                  HeaderFormatError,BootSetEmpty,0));
 
                 Check( Copy (RootStub^^.BootPos,
                              Env^^ÆlocSegmDescr.locPtrIndexÅ) );
                 NoCheck( NextInSet (RootStub^^.BootOwnerSet,
                                       RootStub^^.BootPos) );
                END;
             END;
 
         Loading:
             BEGIN
æ#b#PrintText (' loadmode = fromboot, callmode = loading ');#e#å
 
                if locSegmDescr.noLoadSections > 0 then begin
                  if SameEntity (RootStub^^.BootPos, Void) then
                        Exception(MakeResult(objDirFamily,
                                  HeaderFormatError,BootSetEmpty,0));
                  with s = segm^^, t = rootStub^^.bootPos^^ do begin
                    if elements(s) <> elements(t) then
                      Exception(MakeResult(objDirFamily,HeaderFormatError,
                                           0,0) );
                    CopyBytes ( t, s );
                  end;
 
                   Check( Copy (RootStub^^.BootPos,auxBootPos) );
                   NoCheck( NextInSet (RootStub^^.BootOwnerSet,
                                           RootStub^^.Bootpos) );
                   Check(DeAlloc (RootStub^^.BootOwnerSet,auxBootPos));
                end;
             END;
         END;  (* case callMode *)
    END;  (* fromBoot *)
 
 
    (* fromROM: not implemented *)
 
    END; (* case loadMode *)
 
    headerpos := headerpos + locSegmDescr.size;
 
END;  (* for *)
 
(* Delete Header Segment if creating/loading from Boot Owner Set *)
 
IF loadMode = fromBoot THEN
BEGIN
    Check( DeAlloc (RootStub^^.BootOwnerSet,refHeader) );
END;
 
 
    (*$e*)
(* INSTALL, PART 7 *)
æ#b#PrintText(' Install part 7 ');#e#å
(* Create a security item for the entryNo and make the enntry public.
   Verify the return of a pointer if callMode = creating *)
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
IF NOT (NoProtect OR SameEntity(ThisStub^^.Security , VOID)) THEN
BEGIN
 
    permissions := ÆStubDelete,stubReNameÅ;
        (* these two are always suggested *)
 
    CASE loadMode OF
      fromFile:
        BEGIN
            IF filePermit IN filePerms THEN
                    permissions := permissions + ÆstubpermitÅ;
            IF fileRead IN filePerms OR
               fileExecute IN filePerms THEN
                   permissions := permissions + ÆstubGetRefÅ;
            (* never stubWrite? *)
        END;
 
      fromLoaded:
        BEGIN
            IF stubPermit IN loadPerms THEN
                    permissions := permissions + ÆstubPermitÅ;
            IF stubGetRef IN loadPerms THEN
                    permissions := permissions + ÆstubGetRefÅ;
        END;
 
        (* NoProtect is always set for "fromBoot" and "fromROM",
           cf.part1 *)
 
    END;  (* case *)
 
    Result := ThisStub^^.Security.Create (fullObjName,SystemId,
                                permissions);
    IF Result.main <> ok THEN GOTO exitlabel;
 
END;
 
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
 
(* Make bucket entryNo public *)
 
    Check( ThisStub^^.DirGate.Lock );
 
    WITH d = targetBucket^^.Entries^^, e = d ÆTargetIndexÅ DO
        CASE callMode OF
            creating: e.kind := generalObject;
 
            loading: IF hPrefix.kind = programModule THEN
                        e.kind := loadedProgram
                     ELSE
                        e.kind := loadedLibrary;
 
        END;  (* case *)
 
    Check( ThisStub^^.DirGate.open );
 
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
(* Verify that the caller may have a simple reference to the general
   object returned (only for callMode = creating) *)
 
IF (callMode = creating) AND
   (stubGetRef IN permissions OR
    NoProtect OR
    SameEntity(ThisStub^^.Security , VOID)) THEN
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
    Check( Copy (TargetBucket^^.PtrsÆTargetIndexÅ, Obj) );
 
 
    (*$e*)
(* INSTALL, EXITPART *)
do begin
(* In case of exception in this procedure control is transferred to here
 
   The situation should be reestablished as prior to call. *)
        res := GetException;
printVar ('Install Error ! Result = ', res );
 
        (* It is not necessary to delete the security item,
           since no error arise after its creation! *)
 
        CASE callMode OF
 
            creating: entryNokind := generalObject;
            loading: IF hPrefix.kind = programModule THEN
                        entryNokind := loadedProgram
                     ELSE
                        entryNokind := loadedLibrary;
 
        END;
 
        in
          CleanUpEntry (ThisStub,TargetBucket,TargetIndex,entryNokind);
        do æ nothing å;
 
        (* the fao is closed by implicit deallocation returning from
           the procedure. *)
 
        Exception ( res );
    END;
end; æ exception handling å
 
END;  (*** Install ***)
  (*$e*)
æ!!!!!!!!!!!!!!!!!!!! repair of one pass compiler !!!!!!!!!!!!!!!!!!!!å
function StubTemps: integer; forward;
function StubStack: integer; forward;
 
 
æ---------------- The  S T U B  O B J E C T  ----------------------å
 
 
PROGRAM STUBIMPLEMENT OBJECT ObjDir WITH STUBLOCALS;
 
PROCEDURE CheckNewName (
                     ObjName: fullid; (* complete or shortid *)
                     VAR StubRef: StubLocref;
                     VAR NewShortid: name16;
                     VAR refp, bucket: ref );
 
VAR base: integer;
    entryNo: bucketEntry;
 
(* used by Load, Create, Create Access, and Insert Pointer to find
   the relevant Stub into which the new entity goes *)
 
BEGIN
æ#b#    PrintText (' CheckNewName ');#e#å
 
    Check( Copy (EgoEnv, StubRef) );
    base := 0;
    if elements(objName) < 1 then
      exception(MakeResult(Universal,-DataValueIllegal,nameTooShort,-1));
 
    IF ObjNameÆ1Å <> slash THEN
    BEGIN  (* must be simple shortid *)
        getShortid (ObjName, base, NewShortid);
 
        IF base < LastNonBlank(ObjName) THEN
           Exception(MakeResult(Universal,-DataValueIllegal,nameTooLong,-1));
        IF lookup (EgoEnv,NewShortid,bucket,entryNo,refp) THEN
           Exception(MakeResult(objDirFamily,-ObjectNameExists,0,0) );
 
    END ELSE BEGIN
        (* ObjName is complete *)
 
        GetRefComplete (RootStub,ObjName,base,refp,bucket,entryNo,StubRef);
 
        getShortid (ObjName,base,NewShortid);
 
        IF NewShortid = NULL THEN
           Exception(MakeResult(objDirFamily,
                               -ObjectNameExists,nameTooShort,-1));
            (* because the whole ObjName were scanned by
               GetCompleteRef *)
        IF base < LastNonBlank (Objname) then
          Exception(MakeResult(objDirFamily,
                               -ExtRefNotFound,nameTooLong,-1));
               (* because GetCompleteRef didn't reach the end of ObjName *)
        IF entryNo.kind <> subDir THEN
          Exception(MakeResult(objDirFamily,
                               -ObjectNameExists,nameNotSubDir,-1));
    END;
æ#b#PrintVar (' NewShortId = ',NewShortId);#e#å
    END;  (*** CheckNewName ***)
 
    (*$e*)
PROCEDURE CheckOldName  ( Name: fullid;
                          VAR TargetStub: StubLocref;
                          VAR sid: name16;
                          VAR refp,bucket: ref );
 
    (* Used by Delete, Abort, and Dump to find the relevant
       Stub in which "Name" exists. "Name" must be a complete
       name or a shortid. In the latter case, no searching
       is performed, i.e. the name must be found in this
       Stub ("Name" is thus unambigous) *)
 
    VAR base: integer;
        entryNo: BucketEntry;
    BEGIN
æ#b# PrintText (' CheckOldName '); #e#å
      base := 0;
      if elements(name) < 1 then
        exception(MakeResult(Universal,-DataValueIllegal,nameTooShort,-1));
      IF NameÆ1Å = slash THEN BEGIN
        GetRefComplete (RootStub, Name, base,
                        targetStub,bucket, entryNo, refp);
        IF base < LastNonBlank (Name) THEN
          Exception(MakeResult(objDirFamily,
                               -ExtRefNotFound,nameTooLong,-1));
        sid := entryNo.Name;
      END ELSE BEGIN
        getShortid (Name, base, sid);
        IF base < LastNonBlank (Name) THEN
          Exception(MakeResult(Universal,-DataValueIllegal,nameTooLong,-1));
        Check( Copy (EgoEnv, TargetStub) );
      END;
    END;  (*** CheckOldName ***)
    (*$e*)
    entry Init WITH RECORD
        T1:  ^^;
        INITCONFIG:  ^^;
        initExtension: ref;
        case integer of
        1:( bucket: bucketRef);
        2:(instTmp: installTemps);
        END;
        (* IN Source: AddrMax (optional) *)
 
    VAR SourceAddr: integer;
        i, j: integer;
        size: sizeType;
        name: name16;
    BEGIN
æ#b#        PrintText (' Init ');#e#å
        (* Has Init already been called once? *)
      in
        IF NOT SameEntity(RootStub , VOID) THEN
           Exception(MakeResult(Universal,-EntryIllegal,0,0) );
        SourceAddr := 0; æ!!!!!!!!! Rom Boot not implemented !!!!!!å
 
            PrintText ('--- ObjDir version 0.29  83-11-24 --- ');
 
        (* Allocate Local Data Segm *)
            NoCheck(ClearSize(size));
            NoCheck(AddSeg(size,bytes(stubData)));
            Check( Allocate.NewObj (out localData; size, i ) );
            Check( DeclSeg (LocalData,bytes(stubdata) ) );
 
        (* initialize local data *)
           WITH d = LocalData^^ DO
             d.StubName := RootName;
 
        (* Initialize locals *)
 
        Check( Scheduler.NewGate ( OUT DirGate) );
 
        in
          Check ( Copy(Code,BootPos) );
          Check ( NextInSet ( BootOwnerSet, BootPos ) );
        do begin
          æ Stub is not self in BootSet å
          Check( FirstInSet (BootOwnerSet,BootPos) );
        end;
 
        Check( Copy (EgoEnv,RootStub) );
 
        (* Create Standard name entries *)
 
        GlobalInsertPtr  (EgoEnv,AllocName,Allocate,true,bucket);
        GlobalInsertPtr  (EgoEnv,SchedName,Scheduler,true,bucket);
        GlobalInsertPtr  (EgoEnv,IntName,Intscheduler,true,bucket);
        GlobalInsertPtr  (EgoEnv,ObjDirName,Ego,true,bucket);
 
        (* Make Reentrant *)
 
        Check ( MakeReentrant ( EgoEnv ) );
 
        (* Create InitConfig *)
        name := ConfigName;
        Install (EgoEnv,creating,name,NULL, 0,
                      true (* New Subject *), true (* No Protect *),
                      InitConfig, instTmp );
        Check( allocate.NewObj( out initExtension;
                             makeSize ( initUserSize, initKernelSize), 0 ) );
        Check( CallExtend(initExtension,InitConfig,1)); æ Extended Stack å
        GlobalDelete (EgoEnv,ConfigName, bucket);
  do begin æ error in boot å
    printStack (' !!!!!!!!!!!!!!!!!! B O O T  E R R O R !!!!!!!!!!!!!!!!!' );
  end;
END;  (*** Init ***)
    (*$e*)
entry GetRef WITH Record
    t1: ref;
    workRef1, workRef2, workRef3: ref;
    end;
 
        (* OUT Obj:Ref;
           IN Name: fullid; (complete or simple)
           OUT used: integer;
           OUT kind: ItemKndType *)
 
    BEGIN
æ#b#       PrintText (' GetRef ');#e#å
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
        Result := Allocate.GetId (1, CallersSubject, UserId);
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
        GlobalGetRef (EgoEnv,Name,used,
                      Obj,kind,workRef1,workRef2, workRef3 );
        if elements(name) > used then
        if nameÆused+1Å = slash then used := used + 1;
END; (*** GetRef ***)
    (*$e*)
entry Load WITH RECORD
          T1: ref;
          TARGETSTUB: stubLocRef;
          OBJ: Ref;
          case integer of
          1:( instTmp: installTemps );
          2:( workRef1, workRef2: ref );
          END;
 
        (* INOUT ObjName: fullid;
           IN SourceName: fullid;
           IN NoProtect: protectType   -- optional *)
 
    VAR
        sid: name16;
        NoProtect: boolean;
 
    BEGIN
æ#b#          PrintText (' load ');#e#å
            CheckNewName (ObjName,TargetStub,sid, workRef1, workRef2 );
 
            Install (TargetStub,loading,sid,SourceName,
                     0,false,true,Obj,instTmp );
            with d = targetStub^^.LocalData^^ do
              ConcatNames(d.stubName, sid, objName);
    END;  (*** Load ***)
    (*$e*)
entry Create WITH Record
            T1: ref;
            TargetStub: stubLocRef;
            case integer of
            1:( instTmp: installTemps );
            2:( workRef1, workRef2: ref );
            END;
 
        (* OUT Obj: ref;
           IN OUT ObjName: fullid;
           IN SourceName: fullid;
           IN NoProtect: protectType -- optional
           IN NewSubject: newSubType   -- optional *)
 
    VAR
        sid: name16;
        NewSubject: boolean;
        NoProtect: boolean;
 
    BEGIN
æ#b#            PrintText (' Create ');#e#å
            CheckNewName (ObjName,TargetStub,sid,workRef1, workRef2);
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
            IF NOT NextValArg (NoProtect) THEN NoProtect := false;
            IF NOT NextValArg (NewSubject) THEN NewSubject := false;
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
            NoProtect := true; NewSubJect := false;
            Install (TargetStub,creating,sid,SourceName,
                     0,NewSubject,NoProtect,Obj,instTmp );
 
            with d = targetStub^^.LocalData^^ do
              ConcatNames(d.stubName, sid, objName);
    END;  (*** Create ***)
 
 
    (*$e*)
entry CreateAccess WITH Record
        T1: ref;
        TargetStub: stubLocRef;
        TargetBucket: bucketRef;
        END;
 
        (* OUT Obj: ^^;    simple pointer to the created access obj
           IN Creator: ^^;
           IN Name: fullid; -- complete or simple --
           NoProtect: boolean;
           IN Entry: integer; -- Entry to be called in "creator" *)
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
    VAR
        sid: shortid;
        TargetIndex: integer;
        Result: ResultType;
        i: integer;
        param: ARRAY lo..hi: Natural OF byte;
        permissions: StubSecurityItem;
        fullNewName: fullid;
        SystemId: SubjectIdentification;
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
    BEGIN
æ#b#        PrintText (' create access ');#e#å
      Exception(MakeResult(Universal,-EntryIllegal,0,0) );
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
        CheckNewName (Result Name,TargetStub,sid);
        IF Result.main <> ok THEN ObjReturn (GetException);
 
        IF NOT OccupyFree (TargetStub,sid,TargetBucket,TargetIndex) THEN
           BEGIN
              SetResult (Result,Rejected,NoResources,objDirFamily,0,35);
              ObjReturn(GetException);
           END;
 
        (* Define parameters for the call to "Creator" *)
 
           DefParams (OUT TargetBucket^^ÆTargetIndexÅ);
           FOR i := 3 TO EntryArgs.NoOfFormals DO
               DefParams (INOUT Formal (i));
 
           WHILE NextValArg (param) DO
               DefParams (INOUT param);
 
        Creator.Entry (Result);
        IF Result.main <> ok THEN goto exit;
 
        (* return simple ptr *)
        Result := Copy (TargetBucket^^ÆTargetIndexÅ,Formals(2));
 
    IF NOT SameEntity(Security , void) THEN
    BEGIN (* Create a security item for the access object :)
        permissions := ÆstubDelete,stubReName(?)Å
        WITH d = TargetStub^^.LocalData^^ DO
            concatNames (Result d.StubName,sid,fullNewName);
(* necessary *)
        IF Result.main <> ok THEN GOTO exit (* NameTooLong *)
            Result := Allocate.GetId (1,SystemId);
        IF Result,main <> ok THEN
        GOTO exit;
 
            Result := Security.Create (fullNewName,SystemId,
                             permissions);
        IF Result.main <> ok THEN
        GOTO exit;
    END;
        (* Make the entryNo public *)
        WITH d = TargetBucket^^.Entries^^ DO
            Result := TargetStub^^.DirGate.Lock
                WITH e = dÆTargetIndexÅ DO
                BEGIN
                    e.Name := sid;
                    e.PtrIndex := TargetIndex;
                    e.NoProtect := false;
                                     (* could be returned by creator *)
                    e.kind := Access;
                 END;
             Result := TargetStub^^.DirGate.open;
 
exit:
        IF Result.main <> ok THEN
        BEGIN (* clean up *)
 
            (* No security item exists since no error can arise after
               the "Security.Create" call. *)
 
            CleanUpEntry (EgoEnv,TargetBucket,TargetIndex,Access);
        END;
        ObjReturn (GetException);
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
END;  (*** Create Access ***)
    (*$e*)
entry InsertPointer WITH Record
        T1: ref;
        TargetStub: stubLocRef;
        workRef1, workRef2: ref;
        END;
 
        (* IN Ptr: ref;
           IN Name: fullid; (complete or simple)
           IN NoProtect: protectType *)
 
    VAR
        sid: name16;
 
    BEGIN
æ#b#        PrintText (' InsertPointer ');#e#å
        CheckNewName (Name,TargetStub,sid,workRef1,workRef2);
        GlobalInsertPtr (TargetStub,sid,Ptr,true,workRef1);
    END;  (*** InsertPointer ***)
    (*$e*)
entry ReName
        (* IN OldName,
              NewName: shortid *)
      with record
        t1: ref;
        bucket1,
        bucket2: Bucketref;
        end;
      var
        entryNo1,
        entryNo2: BucketEntry;
        sid1, sid2: name16;
BEGIN
æ#b#     PrintText (' Rename ');#e#å
  FillBytes(' ',sid1);
  FillBytes(' ',sid2);
  if not NameOk(OldName) then
    ObjReturn(MakeResult(Universal,-DataValueIllegal,nameError,-1));
  if not NameOk(NewName) then
    ObjReturn(MakeResult(Universal,-DataValueIllegal,nameError,-2));
  CopyBytes(OldName,sid1);
  CopyBytes(NewName,sid2);
 
  Check ( DirGate.Lock );
  in
 
    IF LookUpEntry (EgoEnv,sid1,bucket1,entryNo1) THEN BEGIN
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
        IF NOT VerifyOperation (StubDelete,EgoEnv,OldName) THEN
        BEGIN
           SetResult (Result,Rejected,ExtRefProtected,objDirFamily,0,51);
           ObjReturn(GetException);
        END;
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
        IF LookUpEntry (EgoEnv,sid2,bucket2,entryNo2) THEN
          Exception(MakeResult(objDirFamily,-ObjectNameExists,0,-2) );
        WITH d = bucket1^^.Entries^^ DO
                dÆentryNo1.indexÅ.Name := sid2;
    END ELSE BEGIN
      Exception(MakeResult(objDirFamily,-ExtRefNotFound,0,-1) );
    END;
  do begin
    check(dirGate.open);
  end;
END; (*** ReName ***)
    (*$e*)
entry DeleteItem WITH Record
            T1: ref;
            TargetStub: stubLocRef;
            workRef1, workRef2: ref;
            END;
 
        (* IN Name: fullid (simple or complete) *)
 
    VAR
        sid: name16;
 
BEGIN
æ#b#    PrintText (' Delete ');#e#å
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
    IF NOT VerifyOperation (stubDelete,EgoEnv,Name) THEN
    BEGIN
       SetResult (Result,Rejected,ExtRefProtected,objDirFamily,0,54);
       ObjReturn(GetException);
    END;
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
    CheckOldName (Name,TargetStub,sid,workRef1, workRef2);
 
    GlobalDelete (TargetStub,sid,workRef1);
END;  (*** Delete ***)
    (*$e*)
entry AbortObj WITH Record
            T1: ref;
            TargetStub: stubLocRef;
            Bucket: bucketRef;
            refp: ref;
            workRef1: ref;
            env: ref;
            END;
 
        (* IN Name = fullid (complete or simple) *)
 
    (* Aborts a Callable Module *)
    VAR i: integer;
        sid: name16;
        entryNo: BucketEntry;
 
    BEGIN
æ#b# PrintText (' Abort '); #e#å
        CheckOldName (Name,TargetStub,sid,refp,workRef1 );
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
        IF NOT VerifyOperation (stubDelete,TargetStub,sid) THEN
        BEGIN
           SetResult (Result,Rejected,ExtRefProtected,objDirFamily,0,70);
        END;
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
 
            IF lookup (TargetStub,sid,bucket,entryNo,refp) THEN
            BEGIN
 
                IF entryNo.kind <> generalObject THEN
                  Exception(MakeResult(Universal,-EntryIllegal,NotCallable,0));
      æ!!!!!!!!!!!!!!!!! order of arguments to inspObj !!!!!!!!!!!!!!!å
              NoCheck( InspObj (TargetStub,env,refp,i) );
              NoCheck( Abort (env) );
            END ELSE
 
             Exception(MakeResult(objDirFamily,-ExtRefNotFound, 0,0));
                (* must have been deleted between calls of
                   "CheckOldName" and "lookup" *)
    END; (*** AbortObj ***)
    (*$e*)
private termSubDir ( objOwner:ref; env: stubLocRef ) WITH Record
          T1:  ^^;
          TargetBucket:  ^^BucketLocals;
          END;
 
        (* Removes the bucket entryNo for a stub being deleted *)
 
    VAR TargetIndex: integer;
 
    BEGIN
        æ#b# PrintText (' termSubDir '); #e#å
        WITH d = env^^.LocalData^^ DO
          targetIndex := d.MotherIndex;
 
        Check ( Copy (env^^.MotherBucket,TargetBucket) );
 
        WITH d = TargetBucket^^.Entries^^ DO
          dÆTargetIndexÅ.kind := FreeEntry;
 
    END;  (*** termSubDir ***)
    (*$e*)
entry NewSubDir WITH Record
          T1: ref;
          targetStub, StubEnv: stubLocRef;
          targetBucket: bucketRef;
          workRef1, workRef2: ref;
          END;
 
        (* OUT ObjDirOwner: ObjDirRefType;
           IN  Name: shortid; *)
 
var
  sid: name16;
  size: sizeType;
  i, targetIndex: integer;
 
BEGIN
æ#b# PrintText (' SubDir '); #e#å
 
    CheckNewName ( name, targetStub, sid, workRef1, workRef2 );
 
    NoCheck(ClearSize (size));
    NoCheck(AddGen (size,refs (StubLocals)));
    NoCheck(AddSeg (size, bytes (StubData)));
 
    Check ( Allocate.NewObj (objDirOwner;size,OUT i ));
 
    Check ( DeclGen (objDirOwner,SubStubs,StubEnv,refs (StubLocals),
             TermSubDir, MakeSize(0,0),MakeSize(-1,-1),StubTemps,
             StubStack,0,addr (stubimplement),
             MakeSize(0,0),true) );
 
    Check ( NewSeg (StubEnv^^.LocalData,bytes( StubData)));
 
    Check ( Copy (code,StubEnv^^.code));
    Check ( Copy (Allocate,StubEnv^^.Allocate));
    Check ( Copy (Scheduler,StubEnv^^.Scheduler));
    Check ( Copy (RootStub,StubEnv^^.RootStub));
    Check ( Copy (StubEnv,StubEnv^^.EgoEnv));
    Check ( Copy (ObjDirOwner,StubEnv^^.Ego));
    Check ( Copy (targetStub,StubEnv^^.MotherStub));
 
    Check ( Scheduler.NewGate (OUT StubEnv^^.DirGate));
 
    GlobalInsertPtr  (StubEnv,ObjDirName,ObjDirOwner,true,
                      targetBucket æworkKpå );
 
    Check ( MakeReentrant ( StubEnv ) );
 
    (* insert bucketEntry *)
 
    IF NOT OccupyFree (targetStub, sid, TargetBucket, TargetIndex) THEN
      Exception(MakeResult(Universal,-NoResources, NoBuckets,0) );
 
    WITH d = TargetBucket^^.Entries^^, e = d ÆTargetIndexÅ DO
    BEGIN
 
      e.Name := sid;
      e.Index := TargetIndex;
      e.NoProtect := true;
 
      (* e.kind is not touched: it is "LockedEntry" until
         further *)
 
    END;
 
    WITH new = StubEnv^^.LocalData^^,
      old = targetStub^^.LocalData^^ DO BEGIN
      new.MotherIndex := targetIndex;
      concatNames(old.stubName, name, new.stubName);
    END;
 
    Check( Copy (targetBucket,StubEnv^^.MotherBucket));
    Check( Copy (StubEnv,targetBucket^^.PtrsÆtargetIndexÅ));
 
   (* Make bucket entryNo public *)
 
    Check( targetStub^^.DirGate.Lock );
 
    WITH d = targetBucket^^.Entries^^, e = d ÆTargetIndexÅ DO
      e.kind := subDir;
 
    Check( targetStub^^.DirGate.open );
 
END;  (*** SubDir ***)
    (*$e*)
entry GetDirName WITH Record  T1: ref;  END;
 
        (* OUT Name: Fullid  (complete) *)
 
    BEGIN
æ#b#        PrintText (' GetDirName ');#e#å
        WITH d = LocalData^^ DO begin
          FillBytes (' ', name );
          CopyBytes (d.StubName, name );
        end;
 
    END; (*** GetStubName ***)
 
 
    (*$e*)
entry InitItemScan WITH Record
            T1: ref;
            Env: scanLocRef;
            END;
 
        (* OUT ScanOwner: IScanRefType       *)
    VAR
        size: SizeType;
        i: integer;
    BEGIN
æ#b# PrintText (' Initscan '); #e#å
 
        NoCheck(Dealloc(bootProc,bootProc)); æremove bootproc, if possibleå
 
        NoCheck(ClearSize(size));
        NoCheck(AddGen (size, refs (ScanLocals)));
        NoCheck(AddEmbSeg (size, bytes (scanData)));
 
        StopCheck(Allocate.NewObj(ScanOwner;size, OUT i));
 
        Check(DeclGen (ScanOwner,ScanSet,env,refs (ScanLocals),
                       0,makeSize(0,0),makeSize(-1,-1),
                       refs (Scanimplement), bytes(ScanImplement),
                       0,addr(ScanImplement),makeSize(0,0),true ));
        Check(NewSeg (env^^.Data,bytes(scanData) ) );
        Check(Copy (EgoEnv,env^^.MotherStub));
        Check(Copy (code, env^^.code ) );
        in
          StopCheck( FirstInSet (Buckets,env^^.currBucket));
        do
          objReturn(MakeResult(objDirFamily,-ExtRefNotFound,0,0));
 
        with env^^.data^^ do lastI := 0;
 
    END;  (*** InitScan ***)
 
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
   entry      PROCEDURE UseAlloc;
 
        (* IN AllocPtr: ^^Alloc;
           IN IdentPtr: ^^Ident *)
    VAR Result: ResultType;
 
    BEGIN
        PrintText (' Use alloc ');
 
        IF NOT SameEntity(IdentObj , void) THEN
        BEGIN
           SetResult (Result,Rejected,EntryIllegal,Universal,0,0);
           ObjReturn(GetException);
        END;
        IF NOT SameEntity(RootStub , EgoEnv) THEN
        BEGIN
           SetResult (Result,Rejected,EntryIllegal,Universal,0,0);
           ObjReturn(GetException);
        END;
        Result:= Copy ( AllocPtr,Allocate);
 
        Result:= Copy ( IdentPtr, IdentObj);
        ObjReturn (GetException);
 
    END;  (*** UseAlloc ***)
 
 
 
 
 
   entry      PROCEDURE Use Security;
 
        (* IN SecurityPtr: ^^SecuritySys;
           IN SystemManPtr: ^^SystemMan *)
 
    VAR Result: ResultType;
 
    BEGIN
        PrintText (' Use Security ');
        IF NOT Security := void THEN Return (Called Once);
        IF NOT RootStub := EgoEnv THEN Return (NotRoot);
        Result:= Copy ( SecurityPtr,Security);
 
        Result:= Copy ( SystemManPtr,SystMan);
        ObjReturn (GetException);
    END;  (*** Use Security ***)
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
 
    (*$e*)
entry SpeedUpObj WITH Record
            T1: ref;
            TargetStub: stubLocRef;
            Bucket: bucketRef;
            refp: ref;
            workRef1: ref;
            env: ref;
            END;
 
        (* IN Name = fullid (complete or simple) *)
 
    (* Speeds up a Callable Module *)
    VAR i: integer;
        sid: name16;
        entryNo: BucketEntry;
 
    BEGIN
æ#b# PrintText (' SpeedUpObj '); #e#å
        CheckOldName (Name,TargetStub,sid,refp,workRef1 );
æØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ
        IF NOT VerifyOperation (stubDelete,TargetStub,sid) THEN
        BEGIN
           SetResult (Result,Rejected,ExtRefProtected,objDirFamily,0,70);
        END;
ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØå
 
            IF lookup (TargetStub,sid,bucket,entryNo,refp) THEN
            BEGIN
 
                IF entryNo.kind <> generalObject THEN
                  Exception(MakeResult(Universal,-EntryIllegal,NotCallable,0));
      æ!!!!!!!!!!!!!!!!! order of arguments to inspObj !!!!!!!!!!!!!!!å
              NoCheck( InspObj (TargetStub,env,refp,i) );
              NoCheck( SpeedUp (env) );
            END ELSE
 
             Exception(MakeResult(objDirFamily,-ExtRefNotFound, 0,0));
                (* must have been deleted between calls of
                   "CheckOldName" and "lookup" *)
    END; (*** speedUpObj ***)
 
otherwise stubOther with record
  t1: ref;
  end;
begin
  Exception(MakeResult(Universal,entryIllegal,0,0) );
end;
 
END; (*****  Stub program *****)
 
æ!!!!!!!!!!!!!!!!!!!! repair of one pass compiler !!!!!!!!!!!!!!!!!!!!å
function StubTemps;
begin StubTemps := refs (StubImplement); end;
 
function StubStack;
begin StubStack := bytes (StubImplement); end;
 
 
initialise stubImplement 'objdir':
allocate 'alloc',
scheduler 'sched',
ego '*',
egoEnv '**'
end.
«eof»