file FilePack.mesa
last modified by Satterthwaite, February 18, 1983 10:07 am
Last Edited by: Maxwell, August 2, 1983 2:40 pm
DIRECTORY
Alloc: TYPE USING [Handle, Notifier, AddNotify, DropNotify, Top, Words],
ConvertUnsafe: TYPE USING [SubString, SubStringToRope],
Copier: TYPE USING [],
FileParms: TYPE USING [ActualId, BindingProc, Ops, Name, nullActual, nullName],
Rope: TYPE USING [Flatten, Length, ROPE],
SymbolTable:
TYPE
USING [
Base, Handle, nullHandle, voidHandle, Acquire, Forget, Locked, Release],
Symbols:
TYPE
USING [
Base, Name, MDRecord, MDIndex, FileIndex,
nullName, CTXNull, IncludedCTXNull, OwnMdi, MDNull, nullFileIndex, mdType],
SymbolOps: TYPE USING [EnterString, SubStringForName],
SymbolPack: TYPE USING [mdLimit, stHandle],
SymbolSegment: TYPE USING [VersionID],
TimeStamp: TYPE USING [Stamp];
FilePack:
PROGRAM
IMPORTS
Alloc, ConvertUnsafe, Rope, SymbolTable, SymbolOps,
own: SymbolPack
EXPORTS Copier = {
OPEN Symbols;
zone: UNCOUNTED ZONE ← NIL;
table: Alloc.Handle ← NIL;
tables defining the current symbol table
mdb: Symbols.Base; -- module directory base
FilePackNotify: Alloc.Notifier = {mdb ← base[mdType]};
included module accounting
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 ← ConvertUnsafe.SubStringToRope[SymbolOps.SubStringForName[formalId]];
td ← ConvertUnsafe.SubStringToRope[SymbolOps.SubStringForName[typeId]];
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]]};
low-level file manipulation
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;
file table management
fileParms: FileParms.Ops;
FileInit:
PUBLIC
PROC [
self: FileParms.ActualId,
ownTable: Alloc.Handle,
scratchZone: UNCOUNTED ZONE,
ops: FileParms.Ops] = {
table ← ownTable; table.AddNotify[FilePackNotify];
zone ← scratchZone;
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;
zone.FREE[@fileTable];
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;
zone.FREE[@fileTable];
zone ← NIL;
table.DropNotify[FilePackNotify]; table ← NIL};
file setup
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 ← ConvertUnsafe.SubStringToRope[SymbolOps.SubStringForName[mdb[mdi].moduleId]];
d2 ← ConvertUnsafe.SubStringToRope[SymbolOps.SubStringForName[mdb[mdi].fileId]];
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]]};
mdi bypass
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;
}.