-- XDFileCache.Mesa -- Edited by: -- Sandman on July 21, 1980 11:17 AM -- Barbara on November 2, 1978 9:24 AM -- Bruce on October 21, 1980 3:50 PM -- Evans on Jun 26, 1980 1:54 PM DIRECTORY AltoFileDefs USING [eofDA, FP, NullFP], DebugOps USING [], DirectoryDefs USING [DirectoryLookup, EnumerateDirectory], DSyms USING [SymbolLock], Inline USING [BITAND, BITOR, COPY], MachineDefs USING [], SegmentDefs USING [ AccessOptions, Append, DefaultAccess, DefaultVersion, EnumerateFiles, FileAccessError, FileHandle, FileNameError, FileObject, FindFile, InsertFile, InvalidFP, LockFile, NewFileOnly, Object, OldFileOnly, OpenFile, Read, ReleaseFile, SetFileAccess, UnlockFile, VersionOptions], Segments USING [], Storage USING [CopyString, FreeString, Node], String USING [AppendString, EquivalentSubStrings, SubStringDescriptor], SwapperOps USING [AllocateObject]; XDFileCache: MONITOR LOCKS DSyms.SymbolLock IMPORTS DirectoryDefs, DSyms, Inline, SegmentDefs, Storage, String, SwapperOps EXPORTS DebugOps, MachineDefs, Segments SHARES SegmentDefs = BEGIN NullFP: AltoFileDefs.FP = AltoFileDefs.NullFP; FileHandle: TYPE = SegmentDefs.FileHandle; NullFileObject: SegmentDefs.FileObject = [ busy: FALSE, body: file[open: FALSE, length: FALSE, lengthvalid: FALSE, read: FALSE, write: FALSE, append: FALSE, lengthchanged: FALSE, lock: 0, swapcount: 0, segcount: 0, fp: NullFP]]; FCRecord: TYPE = RECORD [ name: STRING, fp: AltoFileDefs.FP]; FCSize: CARDINAL = 20; FCLimit: CARDINAL = FCSize-1; FCArray: DESCRIPTOR FOR ARRAY [0..FCSize) OF FCRecord; InitFileCache: PROCEDURE = BEGIN i: CARDINAL; FCArray _ DESCRIPTOR[Storage.Node[FCSize*SIZE[FCRecord]],FCSize]; FOR i IN [0..FCSize) DO FCArray[i] _ FCRecord[NIL,NullFP]; ENDLOOP; cacheInvalid _ FALSE; RETURN END; PromoteFCRecord: PROCEDURE [i: CARDINAL] = BEGIN ithFCR: FCRecord; IF i = FCLimit THEN RETURN; ithFCR _ FCArray[i]; Inline.COPY[to: @FCArray[i], from: @FCArray[i+1], nwords: SIZE[FCRecord]*(FCLimit-i)]; FCArray[FCLimit] _ ithFCR; RETURN END; CopyFileName: PROCEDURE [name: STRING] RETURNS [copy: STRING] = BEGIN IF name = NIL THEN RETURN[NIL]; copy _ Storage.CopyString[name]; RETURN END; AddFCRecord: PROCEDURE [name: STRING, fh: FileHandle] = BEGIN IF FCArray[0].name # NIL THEN Storage.FreeString[FCArray[0].name]; Inline.COPY[to: @FCArray[0], from: @FCArray[1], nwords: SIZE[FCRecord]*(FCSize-1)]; FCArray[FCLimit].name _ CopyFileName[name]; IF fh # NIL THEN FCArray[FCLimit].fp _ fh.fp ELSE FCArray[FCLimit].fp _ NullFP; cacheInvalid _ TRUE; RETURN END; Lookup: PROC [fp: POINTER TO AltoFileDefs.FP, name: STRING] RETURNS [found: BOOLEAN] = BEGIN FOR i: CARDINAL DECREASING IN [0..FCSize) DO IF FCArray[i].name = NIL THEN EXIT; IF EquivalentFileNames[name, FCArray[i].name] THEN { fp^ _ FCArray[i].fp; RETURN[TRUE]}; ENDLOOP; found _ DirectoryDefs.DirectoryLookup[fp,name,FALSE]; END; CacheNewFile: PUBLIC PROCEDURE [ name: STRING, access: SegmentDefs.AccessOptions _ SegmentDefs.DefaultAccess, version: SegmentDefs.VersionOptions _ SegmentDefs.DefaultVersion] RETURNS [file: FileHandle] = BEGIN OPEN AltoFileDefs; i: CARDINAL; create: BOOLEAN; [access,version] _ ValidateOptions[access,version]; create _ Inline.BITAND[version,SegmentDefs.OldFileOnly]=0; file _ NIL; FOR i DECREASING IN [0..FCSize) DO IF FCArray[i].name = NIL THEN BEGIN AddFCRecord[name,NIL]; EXIT END; IF EquivalentFileNames[name, FCArray[i].name] THEN BEGIN PromoteFCRecord[i]; EXIT END; REPEAT FINISHED => AddFCRecord[name,NIL]; ENDLOOP; IF FCArray[FCLimit].fp.leaderDA # eofDA AND ~cacheInvalid THEN BEGIN OPEN SegmentDefs; file _ InsertFile[@FCArray[FCLimit].fp, access]; OpenFile[file ! InvalidFP => GOTO BadCache]; RETURN; EXITS BadCache => BEGIN IF file.segcount = 0 THEN ReleaseFile[file]; cacheInvalid _ TRUE; END; END; ValidateCache[]; SELECT TRUE FROM FCArray[FCLimit].fp.leaderDA # eofDA => file _ SegmentDefs.InsertFile[@FCArray[FCLimit].fp, access]; create => {file _ RealNewFile[name,access]; FCArray[FCLimit].fp _ file.fp}; ENDCASE => ERROR SegmentDefs.FileNameError[name]; RETURN END; FileName, NameForFile: PUBLIC PROCEDURE [name: STRING, file: FileHandle] = BEGIN localname: STRING _ [40]; i: CARDINAL; BEGIN IF cacheInvalid THEN GO TO notincache ELSE FOR i DECREASING IN [0..FCSize) DO IF FCArray[i].name = NIL THEN GO TO notincache; IF FCArray[i].fp = file.fp THEN BEGIN String.AppendString[name,FCArray[i].name]; PromoteFCRecord[i]; RETURN END; REPEAT FINISHED => GO TO notincache; ENDLOOP; EXITS notincache => AddFCRecord[NIL,file]; END; ValidateCache[]; IF FCArray[FCLimit].name = NIL THEN BEGIN FOR i DECREASING IN [1..FCSize) DO FCArray[i] _ FCArray[i-1]; ENDLOOP; FCArray[0] _ [NIL,NullFP]; SIGNAL SegmentDefs.InvalidFP[@file.fp] END ELSE String.AppendString[name,FCArray[FCLimit].name]; RETURN END; EquivalentFileNames: PROCEDURE [n1, n2: STRING] RETURNS [BOOLEAN] = BEGIN s1,s2: String.SubStringDescriptor; s1 _ [base: n1, offset: 0, length: n1.length - (IF n1[n1.length-1] = '. THEN 1 ELSE 0)]; s2 _ [base: n2, offset: 0, length: n2.length - (IF n2[n2.length-1] = '. THEN 1 ELSE 0)]; RETURN[String.EquivalentSubStrings[@s1,@s2]] END; ModifyFile: PUBLIC ENTRY PROCEDURE [name: STRING] RETURNS [BOOLEAN] = BEGIN ENABLE UNWIND => NULL; cap: AltoFileDefs.FP; okay: BOOLEAN _ TRUE; p: POINTER TO StatItem; CheckFHandle: PROCEDURE [file: SegmentDefs.FileHandle] RETURNS [BOOLEAN] = BEGIN IF (file.lock # 0 OR file.segcount # 0) AND file.fp = cap THEN BEGIN SegmentDefs.LockFile[file]; FOR p _ statHead, p.link UNTIL p = NIL DO okay _ okay AND p.proc[name, file] ENDLOOP; SegmentDefs.UnlockFile[file]; okay _ okay AND file.lock = 0 AND file.segcount = 0; IF okay THEN SegmentDefs.ReleaseFile[file]; RETURN[okay]; END; RETURN[FALSE]; END; InvalidateFileCache[]; FOR p _ statHead, p.link UNTIL p = NIL DO okay _ okay AND p.proc[name, NIL] ENDLOOP; IF ~Lookup[@cap, name] THEN RETURN[TRUE]; [] _ SegmentDefs.EnumerateFiles[CheckFHandle]; RETURN[okay]; END; StatItem: TYPE = RECORD [ link: POINTER TO StatItem, proc: PROC[STRING,FileHandle] RETURNS [BOOLEAN]]; statHead: POINTER TO StatItem _ NIL; AddModifyProc: PUBLIC PROC [proc: PROC[STRING,FileHandle] RETURNS [BOOLEAN]] = { p: POINTER TO StatItem = Storage.Node[SIZE[StatItem]]; p^ _ [link: statHead, proc: proc]; statHead _ p}; cacheInvalid: BOOLEAN; InvalidateFileCache: PUBLIC PROCEDURE = BEGIN cacheInvalid _ TRUE END; ValidateCache: PROCEDURE = BEGIN i: CARDINAL; num, found: CARDINAL _ 0; caseBit: WORD = 40B; CheckEntry: PROCEDURE [fp: POINTER TO AltoFileDefs.FP, dirname: STRING] RETURNS[BOOLEAN] = BEGIN fcr: POINTER TO FCRecord _ @FCArray[FCLimit]; THROUGH [0..FCSize) DO IF fcr.name = NIL THEN BEGIN IF fcr.fp.leaderDA = AltoFileDefs.eofDA THEN EXIT; IF fcr.fp = fp^ THEN {fcr.name _ CopyFileName[dirname]; found _ found+1}; END ELSE IF Inline.BITOR[fcr.name[0],caseBit] = Inline.BITOR[dirname[0],caseBit] AND EquivalentFileNames[fcr.name, dirname] THEN {fcr.fp _ fp^; found _ found+1}; fcr _ LOOPHOLE[fcr - SIZE[FCRecord]]; ENDLOOP; RETURN[found = num]; END; IF ~cacheInvalid THEN RETURN; FOR i IN [0..FCSize) DO IF FCArray[i].name # NIL THEN {num _ num+1; FCArray[i].fp _ NullFP; LOOP}; IF FCArray[i].fp.leaderDA # AltoFileDefs.eofDA THEN num _ num+1; ENDLOOP; DirectoryDefs.EnumerateDirectory[CheckEntry]; cacheInvalid _ FALSE; END; RealNewFile: PROCEDURE [name: STRING, access: SegmentDefs.AccessOptions] RETURNS [file: FileHandle] = BEGIN fp: AltoFileDefs.FP; [] _ DirectoryDefs.DirectoryLookup[@fp,name,TRUE]; IF (file _ SegmentDefs.FindFile[@fp]) = NIL THEN BEGIN file _ LOOPHOLE[ SwapperOps.AllocateObject[SIZE[file SegmentDefs.Object]]]; file^ _ NullFileObject; file.fp _ fp; END; SegmentDefs.SetFileAccess[file,access]; RETURN END; ValidateOptions: PROCEDURE [ access: SegmentDefs.AccessOptions, version: SegmentDefs.VersionOptions] RETURNS [SegmentDefs.AccessOptions, SegmentDefs.VersionOptions] = BEGIN OPEN SegmentDefs, Inline; IF access = SegmentDefs.DefaultAccess THEN access _ SegmentDefs.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; InitFileCache[]; END...