-- BcdCIFSLookup.mesa -- Last edited by Satterthwaite on September 15, 1982 10:48 am DIRECTORY Alloc: TYPE USING [AddNotify, Bounds, DropNotify, Handle, Notifier, Top, Words], BcdDefs: TYPE USING [ FTIndex, FTNull, FTRecord, fttype, NameRecord, NullVersion, sstype, sttype], BcdFileDefs: TYPE USING [], BcdOps: TYPE USING [NameString], BcdUtilDefs: TYPE USING [NameForHti], CIFS: TYPE USING [OpenFile, Close, Error, GetFC, Open, read], ConvertUnsafe: TYPE USING [ToRope], File: TYPE USING [Capability], Strings: TYPE USING [ AppendChar, AppendString, String, SubStringDescriptor, SubString], Symbols: TYPE USING [HTIndex, STIndex, STRecord], Table: TYPE USING [Base, Limit]; BcdCIFSLookup: PROGRAM IMPORTS Alloc, BcdUtilDefs, CIFS, ConvertUnsafe, Strings EXPORTS BcdFileDefs = { maxFiles: NAT ~ Table.Limit/BcdDefs.FTRecord.SIZE; FileSequence: TYPE ~ RECORD [SEQUENCE length: [0..maxFiles] OF CIFS.OpenFile]; fileArray: REF FileSequence; nullFile: CIFS.OpenFile ~ NIL; table: Alloc.Handle; zone: UNCOUNTED ZONE; ftb, stb: Table.Base; Notifier: Alloc.Notifier ~ {ftb ← base[BcdDefs.fttype]; stb ← base[BcdDefs.sttype]}; BuildFileTable: PUBLIC PROC [ownTable: Alloc.Handle, scratchZone: UNCOUNTED ZONE] ~ { OPEN Symbols; stLimit: STIndex; zone ← scratchZone; table ← ownTable; table.AddNotify[Notifier]; stLimit ← table.Top[BcdDefs.sttype]; FOR sti: STIndex ← STIndex.FIRST, sti+STRecord.SIZE UNTIL sti=stLimit DO WITH s~~stb[sti] SELECT FROM external => WITH p~~s SELECT FROM file => IF p.fti = BcdDefs.FTNull THEN p.fti ← AddFile[s.hti]; ENDCASE; ENDCASE; ENDLOOP; fileArray ← --zone.--NEW[FileSequence[table.Bounds[BcdDefs.fttype].size/BcdDefs.FTRecord.SIZE]]; FOR i: NAT IN [0..fileArray.length) DO fileArray[i] ← nullFile ENDLOOP}; AddFile: PROC [hti: Symbols.HTIndex] RETURNS [fti: BcdDefs.FTIndex] ~ { ftLimit: BcdDefs.FTIndex ~ table.Top[BcdDefs.fttype]; name: BcdDefs.NameRecord ~ BcdUtilDefs.NameForHti[hti]; FOR fti ← BcdDefs.FTIndex.FIRST, (fti + BcdDefs.FTRecord.SIZE) UNTIL fti = ftLimit DO IF ftb[fti].name = name THEN RETURN ENDLOOP; fti ← table.Words[BcdDefs.fttype, BcdDefs.FTRecord.SIZE]; ftb[fti] ← [name~name, version~BcdDefs.NullVersion]; RETURN}; EraseFileTable: PUBLIC PROC ~ { FOR i: NAT IN [0..fileArray.length) DO IF fileArray[i] # nullFile THEN { CIFS.Close[fileArray[i]]; fileArray[i] ← nullFile}; ENDLOOP; --zone.--FREE[@fileArray]; table.DropNotify[Notifier]; table ← NIL; zone ← NIL}; IndexForFti: PROC [fti: BcdDefs.FTIndex] RETURNS [CARDINAL] ~ INLINE { RETURN [LOOPHOLE[fti, CARDINAL]/BcdDefs.FTRecord.SIZE]}; FtiForIndex: PROC [i: CARDINAL] RETURNS [BcdDefs.FTIndex] ~ INLINE { RETURN [BcdDefs.FTIndex.FIRST + i*BcdDefs.FTRecord.SIZE]}; UnknownFile: PUBLIC ERROR [fti: BcdDefs.FTIndex] ~ CODE; CapabilityForFile: PUBLIC PROC [fti: BcdDefs.FTIndex] RETURNS [File.Capability] ~ { index: CARDINAL ~ IndexForFti[fti]; IF index >= fileArray.length THEN ERROR UnknownFile[fti]; IF fileArray[index] = nullFile THEN { ftb: Table.Base ← table.Bounds[BcdDefs.fttype].base; name: BcdDefs.NameRecord ~ ftb[fti].name; ssb: BcdOps.NameString ← table.Bounds[BcdDefs.sstype].base; ssd: Strings.SubStringDescriptor ← [ base~@ssb.string, offset~name, length~MIN[ssb.size[name], 100]]; nameStr: STRING ← [100]; NormalizeFileName[in~@ssd, out~nameStr]; fileArray[index] ← CIFS.Open[ConvertUnsafe.ToRope[nameStr], CIFS.read ! CIFS.Error => TRUSTED {CONTINUE}]; IF fileArray[index] = nullFile THEN ERROR UnknownFile[fti]}; RETURN [CIFS.GetFC[fileArray[index]]]}; NormalizeFileName: PROC [in: Strings.SubString, out: Strings.String] ~ { char: CHAR; dot: BOOL ← FALSE; out.length ← 0; FOR i: CARDINAL IN [in.offset .. in.offset+in.length) DO SELECT (char ← in.base[i]) FROM IN ['A..'Z] => char ← char + ('a-'A); '. => dot ← TRUE; ENDCASE; Strings.AppendChar[out, char]; ENDLOOP; IF ~dot THEN Strings.AppendString[out, ".bcd"L]}; }.