BcdFileLookup.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Satterthwaite on April 18, 1986 11:55:20 am PST
Maxwell, August 11, 1983 2:39 pm
Paul Rovner, September 8, 1983 5:33 pm
Russ Atkinson, March 7, 1985 0:17:16 am PST
DIRECTORY
Alloc: TYPE USING [AddNotify, Bounds, DropNotify, Handle, Notifier, Top, Words],
Ascii: TYPE USING [Lower],
BcdDefs: TYPE USING [FTIndex, FTNull, FTRecord, fttype, NameRecord, NameString, NullVersion, sstype, sttype],
BcdFileDefs: TYPE USING [],
BcdUtilDefs: TYPE USING [NameForHti],
ConvertUnsafe: TYPE USING [SubString],
FS: TYPE USING [Close, Error, nullOpenFile, Open, OpenFile],
Rope: TYPE USING [Concat, FromProc, ROPE],
Symbols: TYPE USING [HTIndex, STIndex, STRecord],
Table: TYPE USING [Base, Limit];
BcdFileLookup:
PROGRAM
IMPORTS Alloc, Ascii, BcdUtilDefs, FS, Rope
EXPORTS BcdFileDefs = {
maxFiles: NAT ~ Table.Limit/BcdDefs.FTRecord.SIZE;
FileSequence: TYPE ~ RECORD [SEQUENCE length: [0..maxFiles] OF FS.OpenFile];
fileArray: REF FileSequence;
nullFile: FS.OpenFile ~ FS.nullOpenFile;
table: Alloc.Handle;
ftb, stb: Table.Base;
Notifier: Alloc.Notifier ~ {ftb ← base[BcdDefs.fttype]; stb ← base[BcdDefs.sttype]};
BuildFileTable:
PUBLIC
PROC[ownTable: Alloc.Handle] ~ {
OPEN Symbols;
stLimit: STIndex;
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 ← 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 {
fileArray[i].Close[ ! FS.Error => IF error.code = $invalidOpenFile THEN CONTINUE];
fileArray[i] ← nullFile};
ENDLOOP;
FREE[@fileArray];
table.DropNotify[Notifier];
table ← 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[
FS.OpenFile] ~ {
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: BcdDefs.NameString ← table.Bounds[BcdDefs.sstype].base;
ssd: ConvertUnsafe.SubString ← [
base~@ssb.string, offset~name, length~MIN[ssb.size[name], 100]];
fileArray[index] ←
FS.Open[NormalizeFileName[in~ssd]
! FS.Error => TRUSTED {CONTINUE}];
IF fileArray[index] = nullFile THEN ERROR UnknownFile[fti]};
RETURN [fileArray[index]]};
NormalizeFileName:
PROC[in: ConvertUnsafe.SubString]
RETURNS[Rope.
ROPE] = {
dot: BOOL ← FALSE;
i: CARDINAL ← in.offset;
EachChar:
SAFE
PROC
RETURNS[c:
CHAR] ~
TRUSTED {
c ← in.base[i]; i ← i + 1;
SELECT c
FROM
IN ['A..'Z] => c ← Ascii.Lower[c];
'. => dot ← TRUE;
ENDCASE;
RETURN};
name: Rope.ROPE = Rope.FromProc[in.length, EachChar];
RETURN[IF ~dot THEN name.Concat[".bcd"] ELSE name]};
}.