<> <> <> <> <> DIRECTORY Alloc USING [Handle, Notifier, AddNotify, DropNotify, Top, Words], ConvertUnsafe USING [SubString, SubStringToRope], Copier USING [], FileParms USING [ActualId, BindingProc, Ops, Name, nullActual, nullName], Rope USING [Flatten, Length, ROPE], SymbolTable USING [Base, Handle, nullHandle, voidHandle, Acquire, Forget, Locked, Release], Symbols USING [Base, CTXNull, FileIndex, IncludedCTXNull, MDIndex, MDNull, MDRecord, mdType, Name, nullFileIndex, nullName, OwnMdi], SymbolOps USING [EnterString, SubStringForName], SymbolPack USING [mdLimit, stHandle], SymbolSegment USING [VersionID], TimeStamp USING [Stamp]; FilePack: PROGRAM IMPORTS Alloc, ConvertUnsafe, Rope, SymbolTable, SymbolOps, own: SymbolPack EXPORTS Copier = { OPEN Symbols; table: Alloc.Handle _ NIL; <> mdb: Symbols.Base; -- module directory base FilePackNotify: Alloc.Notifier = {mdb _ base[mdType]}; <> VersionStamp: TYPE = TimeStamp.Stamp; FileProblem: PUBLIC SIGNAL [Name] RETURNS [BOOL] = CODE; FileVersion: PUBLIC SIGNAL [Name] RETURNS [BOOL] = CODE; FileVersionMix: PUBLIC SIGNAL [Name] = CODE; AnyVersion: VersionStamp = [net:0, host:0, time:0]; EnterFile: PUBLIC PROC [formalId, typeId: Name, defaultFile: Rope.ROPE] RETURNS [mdi: MDIndex _ MDNull] = { BindItem: FileParms.BindingProc = { IF actual # FileParms.nullActual THEN mdi _ FindMdEntry[typeId, actual.version, EnterRope[actual.locator]] ELSE [] _ SIGNAL FileProblem[formalId]}; -- need better error message fd, td: FileParms.Name; fd _ (SymbolOps.SubStringForName[formalId]).SubStringToRope; td _ (SymbolOps.SubStringForName[typeId]).SubStringToRope; fileParms.Binding[fd, td, defaultFile, BindItem]; RETURN}; FindMdEntry: PUBLIC PROC [id: Name, version: VersionStamp, file: Name] RETURNS [mdi: MDIndex] = { limit: MDIndex = table.Top[mdType]; duplicate: BOOL _ FALSE; FOR mdi _ MDIndex.FIRST, mdi + MDRecord.SIZE UNTIL mdi = limit DO IF mdb[mdi].moduleId = id THEN { IF mdb[mdi].stamp = version THEN RETURN; duplicate _ TRUE}; ENDLOOP; IF duplicate THEN SIGNAL FileVersionMix[id]; mdi _ table.Words[mdType, MDRecord.SIZE]; mdb[mdi] _ MDRecord[ stamp: version, moduleId: id, fileId: file, ctx: IncludedCTXNull, shared: FALSE, exported: FALSE, defaultImport: CTXNull, file: nullFileIndex]; own.mdLimit _ own.mdLimit + MDRecord.SIZE; RETURN}; GetSymbolTable: PUBLIC PROC [mdi: MDIndex] RETURNS [base: SymbolTable.Base] = { index: FileIndex; OpenSymbols[mdi]; index _ mdb[mdi].file; IF fileTable[index].file = nullHandle.file THEN base _ NIL ELSE { base _ SymbolTable.Acquire[fileTable[index]]; IF base.stHandle.versionIdent # SymbolSegment.VersionID THEN { SymbolTable.Release[base]; base _ NIL; IF SIGNAL FileProblem[mdb[mdi].fileId] THEN GO TO flush} ELSE IF base.stHandle.version # mdb[mdi].stamp THEN { SymbolTable.Release[base]; base _ NIL; IF SIGNAL FileProblem[mdb[mdi].fileId] THEN GO TO flush}; EXITS flush => { SymbolTable.Forget[fileTable[index] ! SymbolTable.Locked => {CONTINUE}]; fileParms.Release[fileTable[index]]; fileTable[index] _ voidHandle}}; RETURN}; FreeSymbolTable: PUBLIC PROC [base: SymbolTable.Base] = {SymbolTable.Release[base]}; EnterRope: PROC[rope: Rope.ROPE] RETURNS[Symbols.Name] = INLINE { ss: ConvertUnsafe.SubString; ss.base _ LOOPHOLE[rope.Flatten[]]; ss.offset _ 0; ss.length _ rope.Length[]; RETURN[SymbolOps.EnterString[ss]]}; <> FileHandle: TYPE = SymbolTable.Handle; FileTable: TYPE = RECORD[SEQUENCE length: NAT OF FileHandle]; nullHandle: FileHandle = SymbolTable.nullHandle; voidHandle: FileHandle = SymbolTable.voidHandle; fileTable: REF FileTable; lastFile: INTEGER; <> fileParms: FileParms.Ops; FileInit: PUBLIC PROC [ self: FileParms.ActualId, ownTable: Alloc.Handle, ops: FileParms.Ops] = { table _ ownTable; table.AddNotify[FilePackNotify]; IF FindMdEntry[nullName, self.version, EnterRope[self.locator]] # Symbols.OwnMdi THEN ERROR; fileParms _ ops; fileTable _ NIL; lastFile _ -1}; CreateFileTable: PUBLIC PROC [size: CARDINAL] = { n: CARDINAL = size+1; -- allow for ownMdi fileTable _ NEW[FileTable[n]]; FOR i: FileIndex IN [0..n) DO fileTable[i] _ nullHandle ENDLOOP; lastFile _ -1}; ExpandFileTable: PROC = { newTable: REF FileTable; i: FileIndex; size: CARDINAL = fileTable.length + 2; newTable _ NEW[FileTable[size]]; FOR i IN [0..fileTable.length) DO newTable[i] _ fileTable[i] ENDLOOP; FOR i IN [fileTable.length..size) DO newTable[i] _ nullHandle ENDLOOP; fileTable _ newTable}; FileReset: PUBLIC PROC = { FOR i: INTEGER IN [0..lastFile] DO IF fileTable[i] # nullHandle THEN fileParms.Release[fileTable[i]]; fileTable[i] _ nullHandle; ENDLOOP; table.DropNotify[FilePackNotify]; table _ NIL}; <> MdiToFile: PROC [mdi: MDIndex] RETURNS [FileIndex] = { IF mdb[mdi].file = nullFileIndex THEN { newFile: FileIndex = lastFile + 1; UNTIL newFile < fileTable.length DO ExpandFileTable[] ENDLOOP; fileTable[newFile] _ nullHandle; lastFile _ newFile; mdb[mdi].file _ newFile}; RETURN [mdb[mdi].file]}; OpenSymbols: PROC [mdi: MDIndex] = { index: FileIndex = MdiToFile[mdi]; IF fileTable[index] = nullHandle THEN { d1, d2: FileParms.Name; d1 _ (SymbolOps.SubStringForName[mdb[mdi].moduleId]).SubStringToRope; d2 _ (SymbolOps.SubStringForName[mdb[mdi].fileId]).SubStringToRope; fileTable[index] _ fileParms.Acquire[d1, [mdb[mdi].stamp, d2]]; IF fileTable[index] = nullHandle AND (SIGNAL FileProblem[mdb[mdi].moduleId]) THEN fileTable[index] _ voidHandle}}; TableForModule: PUBLIC PROC [mdi: MDIndex] RETURNS [SymbolTable.Handle] = { RETURN[fileTable[mdb[mdi].file]]}; <> MapSymbols: PUBLIC PROC [id: FileParms.ActualId] RETURNS [base: SymbolTable.Base] = { IF id = FileParms.nullActual THEN base _ NIL ELSE { handle: SymbolTable.Handle = fileParms.Acquire[FileParms.nullName, id]; IF handle.file = nullHandle.file THEN base _ NIL ELSE { base _ SymbolTable.Acquire[handle]; IF base.stHandle.versionIdent # SymbolSegment.VersionID THEN { fileParms.Release[handle]; SymbolTable.Release[base]; base _ NIL}}}; RETURN}; UnmapSymbols: PUBLIC PROC [SymbolTable.Base] = FreeSymbolTable; }.