<<>> <> <> <> <> <> <> <> <> <> <> DIRECTORY Alloc USING [AddNotify, Bounds, DropNotify, Handle, Notifier, Top, Units], MobDefs USING [FTIndex, FTNull, FTRecord, fttype, NameRecord, NullVersion, sstype, sttype], MobFileDefs USING [], MobUtilDefs USING [FreeMob, NameForHti, MobHandle, ReadMob], CinderSysOps USING [Close, Open, OpenKind], ConvertUnsafe USING [SubString, SubStringToRope], IO USING [STREAM], Rope USING [Concat, FromProc, ROPE], MobSymbols USING [HTIndex, STIndex, STRecord], MobMapper USING [BadMobContents], Table USING [Base]; MobFileLookup: PROGRAM IMPORTS Alloc, ConvertUnsafe, MobMapper, MobUtilDefs, CinderSysOps, Rope EXPORTS MobFileDefs = { FileSequence: TYPE ~ RECORD [SEQUENCE length: NAT OF MobUtilDefs.MobHandle]; fileArray: REF FileSequence; table: Alloc.Handle; ftb, stb: Table.Base; Notifier: Alloc.Notifier ~ {ftb ¬ base[MobDefs.fttype]; stb ¬ base[MobDefs.sttype]}; BuildFileTable: PUBLIC PROC[ownTable: Alloc.Handle] ~ { OPEN MobSymbols; stLimit: STIndex; table ¬ ownTable; table.AddNotify[Notifier]; stLimit ¬ table.Top[MobDefs.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 = MobDefs.FTNull THEN p.fti ¬ AddFile[s.hti]; ENDCASE; ENDCASE; ENDLOOP; fileArray ¬ NEW[FileSequence[table.Bounds[MobDefs.fttype].size/MobDefs.FTRecord.SIZE]]; FOR i: NAT IN [0..fileArray.length) DO fileArray[i] ¬ NIL ENDLOOP}; AddFile: PROC[hti: MobSymbols.HTIndex] RETURNS[fti: MobDefs.FTIndex] ~ { ftLimit: MobDefs.FTIndex ~ table.Top[MobDefs.fttype]; name: MobDefs.NameRecord ~ MobUtilDefs.NameForHti[hti]; FOR fti ¬ MobDefs.FTIndex.FIRST, (fti + MobDefs.FTRecord.SIZE) UNTIL fti = ftLimit DO IF ftb[fti].name = name THEN RETURN ENDLOOP; fti ¬ table.Units[MobDefs.fttype, MobDefs.FTRecord.SIZE]; ftb[fti] ¬ [name~name, version~MobDefs.NullVersion]; RETURN}; EraseFileTable: PUBLIC PROC ~ { FOR i: NAT IN [0..fileArray.length) DO IF fileArray[i] # NIL THEN { MobUtilDefs.FreeMob[fileArray[i]]; fileArray[i] ¬ NIL}; ENDLOOP; FREE[@fileArray]; table.DropNotify[Notifier]; table ¬ NIL}; IndexForFti: PROC[fti: MobDefs.FTIndex] RETURNS[CARD] ~ INLINE { RETURN[LOOPHOLE[fti, CARD]/MobDefs.FTRecord.SIZE]}; MobFileErr: PUBLIC ERROR[err: Rope.ROPE] ~ CODE; UnknownFile: PUBLIC ERROR[fti: MobDefs.FTIndex] ~ CODE; CapabilityForFile: PUBLIC PROC[fti: MobDefs.FTIndex] RETURNS[mobh: MobUtilDefs.MobHandle] ~ { index: CARD ~ IndexForFti[fti]; ssd: ConvertUnsafe.SubString; IF index >= fileArray.length THEN ERROR UnknownFile[fti]; IF fileArray[index] = NIL THEN { ftb: Table.Base ¬ table.Bounds[MobDefs.fttype].base; name: MobDefs.NameRecord ~ ftb[fti].name; ssb: LONG STRING ¬ table.Bounds[MobDefs.sstype].base; mobStream: IO.STREAM; ssd ¬ [base~ssb, offset~name+1, length~MIN[ssb.text[name].ORD, 100]]; mobStream ¬ CinderSysOps.Open[NormalizeFileName[in~ssd], $read].stream; IF mobStream = NIL THEN ERROR UnknownFile[fti]; fileArray[index] ¬ MobUtilDefs.ReadMob[mobStream ! MobMapper.BadMobContents => GO TO Oops]; [] ¬ CinderSysOps.Close[mobStream]; IF fileArray[index] = NIL THEN ERROR UnknownFile[fti]; EXITS Oops => ERROR MobFileErr[err: Rope.Concat["MobMapper.BadMobContents raised for ", ConvertUnsafe.SubStringToRope[ssd]]]; }; 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 < c _ Ascii.Lower[c];>> '. => dot ¬ TRUE; ENDCASE; RETURN}; name: Rope.ROPE = Rope.FromProc[MIN[in.length, CARDINAL[in.base.length - in.offset]], EachChar]; RETURN[IF ~dot THEN name.Concat[".mob"] ELSE name]}; }.