-- FileLookup.Mesa; edited by Sandman on July 10, 1980 8:30 AM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AltoFileDefs, DirectoryDefs, FileLookupDefs, InlineDefs, IODefs, Storage, String, SegmentDefs; FileLookup: PROGRAM IMPORTS DirectoryDefs, InlineDefs, IODefs, SegmentDefs, String, Storage EXPORTS FileLookupDefs, SegmentDefs SHARES SegmentDefs = BEGIN OPEN SegmentDefs; FP: TYPE = AltoFileDefs.FP; Entry: TYPE = RECORD [link: POINTER TO Entry, name: STRING, fp: FP]; HashSize: CARDINAL = 19; HashIndex: TYPE = [0..HashSize); HashVector: ARRAY HashIndex OF POINTER TO Entry; HashValue: PROCEDURE [s: STRING] RETURNS [HashIndex] = BEGIN OPEN InlineDefs; i: CARDINAL; i ← BITAND[s[0], 137B] + BITAND[s[s.length/2], 137B]; RETURN[BITXOR[i, s.length*17B] MOD HashSize]; END; InsertEntry: PROCEDURE [name: STRING, fp: POINTER TO FP] = BEGIN hv: HashIndex = HashValue[name]; entry: POINTER TO Entry; entry ← Storage.Node[SIZE[Entry]]; entry.name ← name; entry.fp ← fp↑; entry.link ← HashVector[hv]; HashVector[hv] ← entry; END; FindEntry: PROCEDURE [name: STRING, fp: POINTER TO FP] RETURNS [BOOLEAN] = BEGIN hv: HashIndex = HashValue[name]; entry: POINTER TO Entry; FOR entry ← HashVector[hv], entry.link UNTIL entry = NIL DO IF String.EquivalentString[name, entry.name] THEN BEGIN fp↑ ← entry.fp; RETURN[TRUE]; END; ENDLOOP; RETURN[FALSE]; END; GetFileName: PUBLIC PROCEDURE [file: FileHandle] RETURNS [STRING] = BEGIN hv: HashIndex; entry: POINTER TO Entry; localname: STRING ← [40]; heapname: STRING; FOR hv IN HashIndex DO FOR entry ← HashVector[hv], entry.link UNTIL entry = NIL DO IF entry.fp.serial = file.fp.serial THEN RETURN[entry.name]; ENDLOOP; ENDLOOP; IF ~DirectoryDefs.DirectoryLookupFP[@file.fp, localname] THEN SIGNAL InvalidFP[@file.fp]; heapname ← Storage.CopyString[localname]; InsertEntry[heapname, @file.fp]; RETURN[heapname]; END; NewFile: PUBLIC PROCEDURE [ name: STRING, access: AccessOptions, version: VersionOptions] RETURNS [FileHandle] = BEGIN OPEN InlineDefs; fp: FP; old, create: BOOLEAN; [access, version] ← ValidateOptions[access, version]; create ← BITAND[version, OldFileOnly] = 0; old ← FindEntry[name, @fp]; IF ~old THEN old ← DirectoryDefs.DirectoryLookup[@fp, name, create]; IF (old AND BITAND[version, NewFileOnly] # 0) OR (~old AND ~create) THEN ERROR FileNameError[name]; RETURN[InsertFile[@fp, access]]; END; ValidateOptions: PROCEDURE [access: AccessOptions, version: VersionOptions] RETURNS [AccessOptions, VersionOptions] = BEGIN OPEN InlineDefs; IF access = DefaultAccess THEN access ← Read; -- IF version = DefaultVersion THEN version ← 0; IF BITAND[version, NewFileOnly + OldFileOnly] = NewFileOnly + OldFileOnly OR (BITAND[version, NewFileOnly] # 0 AND BITAND[access, Append] = 0) THEN ERROR FileAccessError[NIL]; IF BITAND[access, Append] = 0 THEN version ← BITOR[version, OldFileOnly]; RETURN[access, version] END; -- FileRequests FileRequest: TYPE = RECORD [link: POINTER TO FileRequest, name: STRING]; RequestHead: POINTER TO FileRequest ← NIL; AddFileRequest: PUBLIC PROCEDURE [name: STRING] = BEGIN r: POINTER TO FileRequest = Storage.Node[SIZE[FileRequest]]; r.name ← name; r.link ← RequestHead; RequestHead ← r; END; FilesMissing: PUBLIC ERROR = CODE; ProcessFileRequests: PUBLIC PROCEDURE = BEGIN r, next: POINTER TO FileRequest; checkone: PROCEDURE [fp: POINTER TO AltoFileDefs.FP, name: STRING] RETURNS [BOOLEAN] = BEGIN r, next: POINTER TO FileRequest; prev: POINTER TO FileRequest ← NIL; FOR r ← RequestHead, next UNTIL r = NIL DO next ← r.link; IF String.EquivalentString[r.name, name] THEN BEGIN InsertEntry[r.name, fp]; IF prev = NIL THEN RequestHead ← next ELSE prev.link ← next; Storage.Free[r]; EXIT; END; prev ← r; ENDLOOP; RETURN[RequestHead = NIL] END; DirectoryDefs.EnumerateDirectory[checkone]; IF RequestHead # NIL THEN BEGIN OPEN IODefs; WriteLine["Files not found:"]; FOR r ← RequestHead, next UNTIL r = NIL DO next ← r.link; WriteChar[' ]; WriteLine[r.name]; Storage.Free[r]; ENDLOOP; RequestHead ← NIL; ERROR FilesMissing; END; END; -- Main body i: HashIndex; FOR i IN HashIndex DO HashVector[i] ← NIL ENDLOOP; END...