-- 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]};
}.