CDIn.mesa
Copyright © 1983, 1984 by Xerox Corporation. All rights reserved.
Last Edited by: Kimr, November 28, 1983 10:22 am
Last Edited by: Jacobi, February 8, 1984 9:41 am
Last Edited by: Jacobi, November 5, 1984 10:53:26 am PST
DIRECTORY
Atom,
CD,
CDApplications,
CDDirectory,
CDEvents,
CDIO,
CDOps USING [CreateDesign],
CDPrivate,
CDProperties,
CDRects,
CDValue,
FileNames,
FS,
IO,
List,
ProcessProps,
Rope,
RuntimeError USING [UNCAUGHT],
TerminalIO,
TokenIO;
CDIn: CEDAR MONITOR
IMPORTS Atom, CD, CDApplications, CDDirectory, CDEvents, CDIO, CDOps, CDPrivate, CDProperties, CDRects, CDValue, FileNames, FS, IO, List, ProcessProps, Rope, RuntimeError, TerminalIO, TokenIO
EXPORTS CDIO
SHARES CDDirectory =
BEGIN
xChipndaleFile: INT = 12121983;
xVersion: INT = 4;
-- global vars
versionKey: PUBLIC INT;
designInReadOperation: PUBLIC CD.Design ← NIL;
binfile: IO.STREAM;
IndexTable: TYPE = RECORD[table: SEQUENCE max: CARDINAL OF CD.ObPtr];
TableTable: TYPE = RECORD[tt: SEQUENCE max: CARDINAL OF REF IndexTable];
fileName: Rope.ROPE;
indexTable: REF IndexTable ← NIL;
tableTable: REF TableTable ← NIL;
maxTableSize: INT = 32000;
GetTableEntry: PROC[i: INT] RETURNS [CD.ObPtr] = INLINE
BEGIN
RETURN[indexTable.table[i]];
IF i<maxTableSize THEN RETURN[indexTable.table[i]]
ELSE RETURN [tableTable.tt[i/maxTableSize-1].table[i MOD maxTableSize]]
END;
SetTableEntry: PROC[i: INT, ob: CD.ObPtr] = INLINE
BEGIN
indexTable.table[i] ← ob;
IF i<maxTableSize THEN indexTable.table[i] ← ob
ELSE tableTable.tt[i/maxTableSize-1].table[i MOD maxTableSize] ← ob
END;
AllocateTables: PROC[i: INT] =
BEGIN
indexTable ← NEW[IndexTable[MIN[i, maxTableSize]]];
IF i>=maxTableSize THEN {
TerminalIO.WriteRope["****design to big\n"];
ERROR
};
IF i>=maxTableSize THEN {
tableTable ← NEW[TableTable[i/maxTableSize]];
FOR n: INT IN [0..i/maxTableSize) DO -- don't be picky with size if it is anyway as big
tableTable.tt[n] ← NEW[IndexTable[maxTableSize]]
ENDLOOP
};
END;
ReadProperties: PUBLIC PROC [] RETURNS [props: CD.Properties←NIL] =
BEGIN
PropertyProblem: PROC [] = {
TerminalIO.WriteRope["**property not readable \n"];
ERROR TokenIO.EncodingError;
};
key: ATOM;
propProcs: CDProperties.PropertyProcs;
token: TokenIO.Token;
DO
token ← TokenIO.ReadToken[];
IF token.ref#$Property THEN {
TokenIO.ReadAgain[];
RETURN [props];
};
key ← TokenIO.ReadPushFlag[];
propProcs ← CDProperties.FetchProcs[key];
IF propProcs#NIL AND propProcs.internalRead#NIL THEN {
props ← Atom.PutPropOnList[propList: props, prop: key, val: propProcs.internalRead[key]];
}
ELSE {
token ← TokenIO.ReadToken[];
IF token.kind=rope OR token.kind=atom OR token.kind=int THEN
props ← Atom.PutPropOnList[propList: props, prop: key, val: token.ref]
ELSE IF token.kind=popFlag THEN {
TokenIO.ReadAgain[];
props ← Atom.PutPropOnList[propList: props, prop: key, val: key]
}
ELSE IF token.kind=pushFlag AND token.ref=NIL THEN {
propertieProps: CD.Properties ← ReadProperties[];
props ← Atom.PutPropOnList[propList: props, prop: key, val: propertieProps];
token ← TokenIO.ReadToken[];
IF token.kind#popFlag THEN PropertyProblem[]
}
ELSE PropertyProblem[]
};
TokenIO.ReadPopFlag[];
ENDLOOP;
END;
SkipThrough: PROC [] =
BEGIN
token: TokenIO.Token;
level: INT ← 0;
DO
token ← TokenIO.ReadToken[];
IF token.kind=pushFlag THEN level ← level+1
ELSE IF token.kind=popFlag THEN level ← level-1;
IF level<0 THEN EXIT;
ENDLOOP;
END;
SetName: PROC[me: CD.ObPtr, r: Rope.ROPE] ~ INLINE {
IF me.p.inDirectory THEN CDDirectory.ObToDirectoryProcs[me].setName[me, r]
};
SetKey: PROC[me: CD.ObPtr, r: Rope.ROPE] ~ INLINE {
IF me.p.inDirectory THEN CDDirectory.ObToDirectoryProcs[me].setKey[me, r]
};
ReadObjectDefinition: PROC [] RETURNS [obj: CD.ObPtr←NIL] =
BEGIN
token: TokenIO.Token;
atom: ATOM = TokenIO.ReadPushFlag[];
p: REF READONLY CD.ObjectProcs ← CD.FetchObjectProcs[atom, designInReadOperation.technology];
IF p=NIL OR p.internalRead=NIL THEN {
TerminalIO.WriteRope["unknown object "];
TerminalIO.WriteRope[Atom.GetPName[atom]];
TerminalIO.WriteLn[];
SkipThrough[];
obj ← CDRects.CreateBareRect[[10, 10], CD.highLightError];
}
ELSE {
obj ← p.internalRead[];
IF obj=NIL THEN obj ← CDRects.CreateBareRect[[10, 10], CD.highLightError];
IF versionKey>0 THEN {
IF p.inDirectory THEN {
name: Rope.ROPE ← TokenIO.ReadRope[];
key: Rope.ROPE ← TokenIO.ReadRope[];
SetName[obj, name];
SetKey[obj, key];
};
};
token ← TokenIO.ReadToken[];
IF token.kind#popFlag THEN {
TokenIO.ReadAgain[];
obj.properties ← ReadProperties[];
TokenIO.ReadPopFlag[];
}
}
END;
ReadObject: PUBLIC PROC [] RETURNS [CD.ObPtr] =
BEGIN
t: TokenIO.Token = TokenIO.ReadToken[];
IF t.kind=int THEN { -- instance
ins: INTNARROW[t.ref, REF INT]^;
RETURN [GetTableEntry[ins]]
};
TokenIO.ReadAgain;
RETURN [ReadObjectDefinition[]]
END;
ReadApplicationPtr: PUBLIC PROC [] RETURNS [CD.ApplicationPtr] =
BEGIN
RelativeMode: PROC [] RETURNS [BOOL] = INLINE {
RETURN [versionKey>=3]
};
ap: CD.ApplicationPtr;
location: CD.DesignPosition ← ReadPosition[];
orientation: CD.Orientation ← CDIO.ReadOrientation[];
properties: CD.Properties ← ReadProperties[];
ob: CD.ObPtr ← ReadObject[];
IF RelativeMode[] THEN
ap ← CDApplications.NewApplicationI[ob: ob, location: location, orientation: orientation, properties: properties]
ELSE
ap ← NEW[CD.Application ← [location: location, orientation: orientation, properties: properties, ob: ob, selected: FALSE]];
RETURN [ap];
END;
ReadApplicationList: PUBLIC PROC [] RETURNS [list: CD.ApplicationList←NIL] =
BEGIN
num: INT = TokenIO.ReadInt[];
THROUGH [0..num) DO
list ← CONS[ReadApplicationPtr[], list];
ENDLOOP
END;
ReadPushRec: PROC [] RETURNS [pr: CD.PushRec] =
BEGIN
token: TokenIO.Token ← TokenIO.ReadToken[];
dummy: CD.ObPtr;
IF token.ref=$Nil THEN pr.mightReplace←NIL
ELSE {
TokenIO.ReadAgain[];
pr.mightReplace ← ReadApplicationPtr[];
};
dummy ← ReadObjectDefinition[];
pr.changed ← pr.indirectlyChanged ← TRUE;
pr.specific ← NARROW[dummy.specificRef, CD.CellPtr];
pr.dummyCell ← CDApplications.NewApplicationI[ob: dummy];
END;
ReadPosition: PROC [] RETURNS [pos: CD.DesignPosition] =
BEGIN
pos.x ← TokenIO.ReadInt[];
pos.y ← TokenIO.ReadInt[];
END;
ReadLevel: PUBLIC PROC [] RETURNS [CD.Level] =
BEGIN
key: ATOM = TokenIO.ReadAtom[];
RETURN [CD.FetchLevel[designInReadOperation.technology, key]];
END;
ReadDesignData: PROC [] =
BEGIN
index, directoryCount: INT;
token: TokenIO.Token;
obj: CD.ObPtr;
directoryCount ← TokenIO.ReadInt[];
AllocateTables[directoryCount+1]; -- ???
FOR n: INT IN [1..directoryCount] DO
index ← TokenIO.ReadInt[];
obj ← ReadObjectDefinition[];
SetTableEntry[index, obj];
IF versionKey=0 THEN {
token ← TokenIO.ReadToken[];
WHILE token.kind=rope DO
name: Rope.ROPE = NARROW[token.ref];
obx: INT = TokenIO.ReadInt[];
[] ← CDDirectory.Include[designInReadOperation, GetTableEntry[obx], name];
token ← TokenIO.ReadToken[];
ENDLOOP;
TokenIO.ReadAgain[];
}
ELSE IF obj.p.inDirectory THEN {
name: Rope.ROPE = CDDirectory.Name[obj];
[] ← CDDirectory.Include[designInReadOperation, obj, name];
}
ENDLOOP;
designInReadOperation.properties ← ReadProperties[];
designInReadOperation.actual ← NIL;
DO
token ← TokenIO.ReadToken[];
IF token.ref#$Push THEN {
TokenIO.ReadAgain[];
EXIT;
};
designInReadOperation.actual ← CONS[ReadPushRec[], designInReadOperation.actual];
ENDLOOP;
token ← TokenIO.ReadToken[];
IF token.ref#$EndOfDesign THEN ERROR TokenIO.EncodingError;
END;
ReadDesign: PUBLIC ENTRY PROC [from: REFNIL, check: PROC [CD.Design] RETURNS [BOOL] ← NIL] RETURNS [CD.Design] =
--from is either a IO.STREAM, a Rope.ROPE, or NIL
--check: (called if non NIL), is called after technology and design-name is initialized
--  read proceeds only if check returns TRUE
--returns NIL if design not read in successfully
--viewer is not opened
BEGIN
ENABLE UNWIND => {
indexTable ← NIL;
tableTable ← NIL;
designInReadOperation ← NIL;
};
design: CD.Design; -- is initialized before return only
-- all internal routines use designInReadOperation in place of design
DoReadDesign: INTERNAL PROC [check: PROC [CD.Design] RETURNS [BOOL]] =
-- result design returned in designInReadOperation
-- handles all the TokenIO business
BEGIN
ENABLE {
CDPrivate.DebugCall => REJECT;
RuntimeError.UNCAUGHT => {
designInReadOperation ← NIL;
TerminalIO.WriteRope["unknown problem while reading; it is ok to abort\n"];
CDPrivate.Debug["unknown error in reading"];
GOTO DoReturn;
};
TokenIO.EncodingError => {
designInReadOperation ← NIL;
TerminalIO.WriteRope["TokenIO encoding problem; it is ok to abort\n"];
CDPrivate.Debug["read error in encoding"];
GOTO DoReturn;
};
};
DoWhileAttached: INTERNAL PROC [] =
--and always Release
BEGIN
ENABLE UNWIND => {
designInReadOperation ← NIL;
TokenIO.ReleaseReader[];
};
TechnologyCheck: INTERNAL PROC [] =
--Side-effect: if bad, designInReadOperation is set to NIL
BEGIN
ENABLE UNWIND => {designInReadOperation ← NIL};
dont: BOOL ← CDEvents.ProcessEvent[
ev: readEvent,
design: designInReadOperation,
x: NIL,
listenToDont: TRUE
].dont;
IF dont THEN {
designInReadOperation ← NIL;
TerminalIO.WriteRope["Technology rejects read\n"];
}
END;
VersionAndSealCheck: INTERNAL PROC [] =
BEGIN
--chipndale check
IF TokenIO.ReadInt[]#xChipndaleFile THEN {
TerminalIO.WriteRope["File is not a chipndale design\n"];
ERROR TokenIO.Error[other, "chipndale filekey"];
};
--version check
versionKey ← TokenIO.ReadInt[];
IF versionKey#xVersion THEN {
IF versionKey>xVersion THEN { -- too new
TerminalIO.WriteRope["design was written with newer chipndaleversion\n"];
TerminalIO.WriteRope["get a new chipndale version\n"];
ERROR TokenIO.Error[other, "chipndale versionkey"];
}
ELSE IF versionKey IN [2..xVersion] THEN { -- not new but dont tell it
NULL
}
ELSE IF versionKey IN [1..xVersion] THEN { -- not new but everything ok
TerminalIO.WriteRope["design was written with older chipndaleversion\n"];
}
ELSE IF versionKey IN [0..xVersion] THEN { -- not new but please convert
TerminalIO.WriteRope["design was written with older chipndaleversion\n"];
TerminalIO.WriteRope["Please convert also your other designs\n"];
}
ELSE { -- too old
TerminalIO.WriteRope["design was written with older chipndaleversion\n"];
TerminalIO.WriteRope["This version is no more supported\n"];
ERROR TokenIO.Error[other, "chipndale versionkey"];
};
};
--seal check
IF versionKey>0 THEN {
IF TokenIO.ReadInt[]#-1 THEN {
TerminalIO.WriteRope["File had not been properly closed; has bad seal\n"];
ERROR TokenIO.Error[other, "file had not been properly closed"];
};
};
END;
-- DoWhileAttached
VersionAndSealCheck[];
technologyKey ← TokenIO.ReadAtom[];
technologyName ← TokenIO.ReadRope[];
technology ← CD.FetchTechnology[technologyKey];
IF technology=NIL THEN {
TerminalIO.WriteRope["technology '"];
TerminalIO.WriteRope[technologyName];
TerminalIO.WriteRope["' not loded\n"];
GOTO NotDoneAndRelease
};
designInReadOperation ← CDOps.CreateDesign[technology];
TechnologyCheck[];
IF designInReadOperation=NIL THEN GOTO NotDoneAndRelease;
designInReadOperation.name ← TokenIO.ReadRope[];
IF Rope.IsEmpty[designInReadOperation.name] THEN designInReadOperation.name ← fileName;
IF check#NIL THEN {
IF NOT check[designInReadOperation] THEN GOTO NotDoneAndRelease;
};
ReadDesignData[];
TokenIO.ReleaseReader[];
CDValue.Store[boundTo: designInReadOperation, key: $CDxFromFile, value: fileName];
EXITS
NotDoneAndRelease => {
designInReadOperation ← NIL;
TokenIO.ReleaseReader[];
};
END;
-- DoReadDesign
technology: CD.Technology;
technologyKey: ATOM;
technologyName: Rope.ROPE;
designInReadOperation ← NIL;
TokenIO.AttachReader[binfile !
TokenIO.Error => {
r: Rope.ROPE ← "bad explanation";
IF ISTYPE[explanation, Rope.ROPE] THEN r←NARROW[explanation];
TerminalIO.WriteRope[r];
TerminalIO.WriteRope["... not attached\n"];
GOTO NotAttached
}
];
DoWhileAttached[];
EXITS
NotAttached, DoReturn => RETURN
END;
ReadName: PROC [] RETURNS [name: Rope.ROPE] =
BEGIN
wDir: Rope.ROPE ← FileNames.CurrentWorkingDirectory[];
TerminalIO.WriteRope[" input file"];
IF wDir#NIL THEN {
TerminalIO.WriteRope[" ("];
TerminalIO.WriteRope[wDir];
TerminalIO.WriteRope[")"];
};
name ← TerminalIO.RequestRope[" > "];
END;
-- begin ReadDesign
iDidTheOpen: BOOLFALSE;
name: Rope.ROPE;
-- open file; assign fileName and binfile
IF from#NIL AND ISTYPE[from, IO.STREAM] THEN {
fileName ← NIL;
binfile ← NARROW[from, IO.STREAM]
}
ELSE {
IF from=NIL THEN name ← ReadName[]
ELSE IF ISTYPE[from, Rope.ROPE] THEN {
name ← NARROW[from, Rope.ROPE];
IF Rope.IsEmpty[name] THEN name ← ReadName[];
}
ELSE {
TerminalIO.WriteRope["ReadDesign does not support type of 'from' parameter\n"];
GOTO NotOpened;
};
fileName ← MakeName[name, "dale"];
binfile ← FS.StreamOpen[fileName ! FS.Error =>
IF error.group # bug THEN {
TerminalIO.WriteRope[fileName];
TerminalIO.WriteRope[" not opened: "];
TerminalIO.WriteRope[error.explanation];
TerminalIO.WriteLn[];
GOTO NotOpened;
}];
iDidTheOpen ← TRUE;
TerminalIO.WriteRope[fileName];
TerminalIO.WriteRope[" opened \n"];
};
-- do the actual work
DoReadDesign[check];
design ← designInReadOperation;
-- finalize
designInReadOperation ← NIL;
indexTable ← NIL;
tableTable ← NIL;
IF iDidTheOpen THEN IO.Close[binfile];
RETURN [design];
EXITS
NotOpened => {
indexTable ← NIL;
tableTable ← NIL;
designInReadOperation ← NIL;
TerminalIO.WriteRope["Read not done\n"];
RETURN [NIL];
}
END;
ReadOrientation: PUBLIC PROC [] RETURNS [orientation: CD.Orientation] =
BEGIN
i: INT = TokenIO.ReadInt[];
IF versionKey<=3 THEN {
IF i IN [0..15] THEN orientation ← i/4*2 + i MOD 2 ELSE ERROR TokenIO.EncodingError;
}
ELSE
IF i IN [0..7] THEN orientation ← i ELSE ERROR TokenIO.EncodingError
END;
-- Working directories ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CheckWorkingDirectory: PROC [wDir: Rope.ROPE] RETURNS [slashWDir: Rope.ROPE] =
--if wDir is a directory, assign it to slashWDir
--else slashWDir ← nil
INLINE BEGIN
IF FileNames.IsADirectory[wDir] AND NOT FileNames.IsAPattern[wDir] THEN {
length: INT;
slashWDir ← FileNames.ConvertToSlashFormat[wDir];
length ← slashWDir.Length[];
IF slashWDir = wDir AND length > 0 AND slashWDir.Fetch[length - 1] = '/ THEN {
RETURN [slashWDir];
}
};
RETURN [NIL]
END;
SetWorkingDirectory: PUBLIC PROC [design: REF, wDir: Rope.ROPE] =
BEGIN
wDir ← CheckWorkingDirectory[wDir].slashWDir;
CDValue.Store[boundTo: design, key: $WorkingDirectory, value: wDir];
END;
GetWorkingDirectory: PUBLIC PROC [design: REF] RETURNS [wDir: Rope.ROPENIL] =
BEGIN
WITH CDValue.Fetch[boundTo: design, key: $WorkingDirectory, propagation: global] SELECT FROM
r: Rope.ROPE => RETURN [CheckWorkingDirectory[r].slashWDir];
ENDCASE => RETURN [NIL]
END;
UseWorkingDirectory: PUBLIC PROC [design: REF] RETURNS [wDir: Rope.ROPE] =
--set's it for the running process
--return's it
BEGIN
wDir ← GetWorkingDirectory[design];
IF wDir#NIL THEN {
[] ← List.PutAssoc[key: $WorkingDirectory, val: wDir, aList: ProcessProps.GetPropList[]];
RETURN [wDir];
};
RETURN [FileNames.CurrentWorkingDirectory[]]
END;
TrailingChar: PROC [base: Rope.ROPE, char: CHAR] RETURNS [INT] = {
--position of last "char", only before '!, '], '>, '/ considered
len: INT ← Rope.Length[base];
pos: INT ← len;
WHILE pos > 0 DO
SELECT Rope.Fetch[base, pos ← pos - 1] FROM
char => RETURN [pos];
'!, '], '>, '/ => EXIT;
ENDCASE;
ENDLOOP;
RETURN [len];
};
MakeName: PUBLIC PROC [base: Rope.ROPE,
ext: Rope.ROPENIL, wDir: Rope.ROPENIL, modifier: Rope.ROPENIL] RETURNS [Rope.ROPE] =
BEGIN
bang: INT = TrailingChar[base, '!];
--remove version number
r: Rope.ROPE ← base.Substr[len: bang];
dot: INT ← TrailingChar[r, '.];
--include modifier
IF ~modifier.IsEmpty[] THEN r ← r.Concat[modifier];
--include extension
IF ~ext.IsEmpty[] AND (dot >= r.Length[]) THEN {
dot2: INT ← TrailingChar[ext, '.];
IF dot2 >= ext.Length[] THEN r ← r.Cat[".", ext]
ELSE r ← r.Concat[ext.Substr[dot2]]
};
--include working directory
IF wDir#NIL THEN {
IF r.IsEmpty[] OR (r.Fetch[]#'/ AND r.Fetch[]#'[) THEN
r ← FileNames.Directory[wDir].Concat[r]
};
--put version number back
IF bang < Rope.Length[base] THEN {
r ← r.Concat[base.Substr[bang]]
};
RETURN [r]
END;
NewDesignHasBeenCreated: CDEvents.EventProc =
-- PROC [event: REF, design: CD.Design, x: REF] --
--repaint captions and sometimes the contents
BEGIN
SetWorkingDirectory[design, FileNames.CurrentWorkingDirectory[]];
END;
-- Module Initialization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
readEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$ReadTechnologyPrivate];
CDValue.EnregisterKey[key: $WorkingDirectory];
CDEvents.RegisterEventProc[$CreateNewDesign, NewDesignHasBeenCreated];
END.
versionKey 0
versionKey 1: objects with children carry names
versionKey 2:
versionKey 3: June 15, 1984 3:46:13 pm PDT; applications position is its innerrect; this allows to shrink or grow the nwell from cmos
versionKey 4: October 20, 1984 9:36:34 am PDT; orientation changed