CDIn.mesa
Copyright © 1983, 1984, 1985, 1986, 1987 by Xerox Corporation. All rights reserved.
Last Edited by: Kimr, November 28, 1983 10:22 am
Last Edited by: Christian Jacobi, February 8, 1984 9:41 am
Last Edited by: Christian Jacobi, May 29, 1987 11:58:39 am PDT
DIRECTORY
Atom,
Ascii,
BasicTime,
Commander,
CD,
CDBasics,
CDCells,
CDDirectory,
CDEnvironment,
CDEvents,
CDInstances,
CDImports,
CDIO,
CDRepetitions,
CDSequencer USING [CheckAborted],
CDOps,
CDPrivate,
CDProperties,
CDRects,
CDValue,
Convert,
FileNames,
FS,
IO,
Properties,
RefTab,
Rope,
RuntimeError USING [UNCAUGHT],
TerminalIO,
TokenIO;
CDIn:
CEDAR
PROGRAM
IMPORTS Atom, BasicTime, Convert, CD, CDBasics, CDCells, CDDirectory, CDEnvironment, CDEvents, CDInstances, CDIO, CDOps, CDPrivate, CDProperties, CDRects, CDSequencer, CDValue, FileNames, FS, IO, Properties, RefTab, Rope, RuntimeError, TerminalIO, TokenIO
EXPORTS CDIO
SHARES CD, CDDirectory =
BEGIN
xChipndaleFile: INT = 12121983;
xVersion: INT = 18;
Version:
PROC [h: TokenIO.Handle]
RETURNS [
INT] =
INLINE {
RETURN [IF h.oldVersion THEN VersionKey[h] ELSE xVersion ]
};
IndexTable: TYPE = RECORD[table: SEQUENCE max: CARDINAL OF CD.Object];
TableTable: TYPE = RECORD[tt: SEQUENCE max: CARDINAL OF REF IndexTable];
maxTableSize: INT = 32000;
signalOnPropertyProblem: BOOL ← TRUE; --set variable with debugger
GetTableEntry:
PROC[h: TokenIO.Handle, i:
INT]
RETURNS [ob:
CD.Object←
NIL] =
INLINE {
IF i<maxTableSize
THEN {
indexTable: REF IndexTable ← NARROW[Properties.GetProp[h.properties^, $IndexTable]];
ob ← indexTable.table[i];
}
ELSE {
tableTable: REF TableTable ← NARROW[Properties.GetProp[h.properties^, $TableTable]];
ob ← tableTable.tt[i/maxTableSize-1].table[i MOD maxTableSize];
};
IF ob=NIL THEN TerminalIO.PutRope["*** read object failed\n"];
};
SetTableEntry:
PROC[h: TokenIO.Handle, i:
INT, ob:
CD.Object] =
INLINE {
IF i<maxTableSize
THEN {
indexTable: REF IndexTable ← NARROW[CDProperties.GetPRefProp[h.properties, $IndexTable]];
indexTable.table[i] ← ob
}
ELSE {
tableTable: REF TableTable ← NARROW[CDProperties.GetPRefProp[h.properties, $TableTable]];
tableTable.tt[i/maxTableSize-1].table[i MOD maxTableSize] ← ob;
}
};
AllocateTables:
PROC[h: TokenIO.Handle, i:
INT] = {
indexTable: REF IndexTable ← NEW[IndexTable[MIN[i, maxTableSize]]];
CDProperties.PutPRefProp[h.properties, $IndexTable, indexTable];
IF i>=maxTableSize
THEN {
tableTable: REF TableTable ← NEW[TableTable[i/maxTableSize]];
CDProperties.PutPRefProp[h.properties, $TableTable, tableTable];
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
};
};
NoteError:
PROC [h: TokenIO.Handle, x:
REF] = {
IF x=NIL THEN x ← $TRUE;
CDProperties.PutPRefProp[h.properties, $errorObject, x];
};
ReadProperties:
PUBLIC
PROC [h: TokenIO.Handle]
RETURNS [props:
CD.PropList←
NIL] = {
PropertyProblem:
PROC [h: TokenIO.Handle, key:
ATOM←
NIL, skip:
BOOL←
FALSE] = {
TerminalIO.PutRope["**** property not readable"];
IF key#
NIL
THEN {
TerminalIO.PutRopes["; probably ", Atom.GetPName[key]];
};
TerminalIO.PutRope["\n"];
IF signalOnPropertyProblem THEN SIGNAL TokenIO.EncodingError;
IF skip THEN TokenIO.Skip[h];
};
CheckNoRegistration:
PROC [a:
ATOM]
RETURNS [ok:
BOOL] = {
--ok means NOT registered
propProcs: CDProperties.PropertyProcs ← CDProperties.FetchProcs[a];
ok ← propProcs=NIL OR propProcs.internalRead=NIL;
IF ~ok
THEN {
TerminalIO.PutRope["**** property registered and not readable"];
PropertyProblem[h, a];
};
};
ExplicitProperty:
PROC [h: TokenIO.Handle] = {
key: ATOM; propProcs: CDProperties.PropertyProcs;
token: TokenIO.Token ← TokenIO.Read[h];
WITH token
SELECT
FROM
push2: TokenIO.Token.push2 => key ← push2.value;
push: TokenIO.Token.push => {
--only old version may use that !
IF Version[h]>=16 THEN SIGNAL TokenIO.EncodingError;
key ← push.value;
};
ENDCASE => SIGNAL TokenIO.EncodingError;
propProcs ← CDProperties.FetchProcs[key];
IF propProcs#
NIL
AND propProcs.internalRead#
NIL
THEN {
props ← Properties.PutProp[props, key, propProcs.internalRead[h, key]];
}
ELSE
IF Version[h]>=12
THEN {
n: Rope.ROPE ← Atom.GetPName[key];
TerminalIO.PutRopes["**** property ", n, " not registered\n"];
CDEnvironment.ExecFileEntry[n, CDIO.DesignInReadOperation[h].technology];
propProcs ← CDProperties.FetchProcs[key];
IF propProcs#
NIL
AND propProcs.internalRead#
NIL
THEN {
props ← Properties.PutProp[props, key, propProcs.internalRead[h, key]];
}
ELSE {
TerminalIO.PutRope["failed"];
IF signalOnPropertyProblem THEN SIGNAL TokenIO.EncodingError;
};
}
ELSE OldDefaultProperty[key];
TokenIO.ReadPop[h ! TokenIO.EncodingError => PropertyProblem[h, key, TRUE]];
};
DefaultProperty:
PROC [h: TokenIO.Handle] = {
PushCase:
PROC [key:
ATOM] = {
IF CheckNoRegistration[key]
THEN {
SELECT TokenIO.ReadAtom[h]
FROM
$properties => {
propertieProps: CD.PropList ← ReadProperties[h];
props ← Properties.PutProp[props, key, propertieProps];
};
$layer => {
layer: CD.Layer ← ReadLayer[h];
props ← Properties.PutProp[props, key, CDPrivate.layers[layer]]
};
$ropeList => {
rList: LIST OF Rope.ROPE ← NIL;
DO
token: TokenIO.Token ← TokenIO.Read[h];
WITH token
SELECT
FROM
rope: TokenIO.Token.rope => rList ← CONS[rope.value, rList];
ENDCASE => {
TokenIO.ReadAgain[h, token];
props ← Properties.PutProp[props, key, rList];
EXIT;
}
ENDLOOP
};
ENDCASE => PropertyProblem[h, key, FALSE];
TokenIO.ReadPop[h ! TokenIO.EncodingError => PropertyProblem[h, key, TRUE]];
};
};
token: TokenIO.Token ← TokenIO.Read[h];
WITH token
SELECT
FROM
atom: TokenIO.Token.atom =>
IF CheckNoRegistration[atom.value]
THEN {
token: TokenIO.Token ← TokenIO.Read[h];
WITH token
SELECT
FROM
ropex: TokenIO.Token.rope =>
props ← Properties.PutProp[props, atom.value, ropex.value];
atomx: TokenIO.Token.atom =>
props ← Properties.PutProp[props, atom.value, atomx.value];
intx: TokenIO.Token.int =>
props ← Properties.PutProp[props, atom.value, NEW[INT←intx.value]];
ENDCASE => PropertyProblem[h, atom.value];
};
push2: TokenIO.Token.push2 => PushCase[push2.value];
push: TokenIO.Token.push => {
IF Version[h]>=16 THEN SIGNAL TokenIO.EncodingError;
PushCase[push.value];
};
ENDCASE => PropertyProblem[h, NIL];
};
OldDefaultProperty:
PROC [key:
ATOM] = {
token: TokenIO.Token ← TokenIO.Read[h];
WITH token
SELECT
FROM
rope: TokenIO.Token.rope =>
props ← Properties.PutProp[props, key, rope.value];
atom: TokenIO.Token.atom =>
props ← Properties.PutProp[props, key, atom.value];
int: TokenIO.Token.int =>
props ← Properties.PutProp[props, key, NEW[INT←int.value]];
pop: TokenIO.Token.pop => {
TokenIO.ReadAgain[h, token];
props ← Properties.PutProp[props, key, key]
};
push: TokenIO.Token.push => {
IF push.value=
NIL
OR push.value=$properties
THEN {
propertieProps: CD.PropList ← ReadProperties[h];
props ← Properties.PutProp[props, key, propertieProps];
}
ELSE
IF push.value=$layer
THEN {
layer: CD.Layer ← ReadLayer[h];
props ← Properties.PutProp[props, key, CDPrivate.layers[layer]]
}
ELSE PropertyProblem[h, key];
TokenIO.ReadPop[h ! TokenIO.EncodingError => PropertyProblem[h, key]];
};
ENDCASE => PropertyProblem[h, key];
};
DO
token: TokenIO.Token ← TokenIO.Read[h];
WITH token
SELECT
FROM
atom: TokenIO.Token.atom =>
SELECT atom.value
FROM
$Property => ExplicitProperty[h];
$DefaultProperty => DefaultProperty[h];
ENDCASE => {TokenIO.ReadAgain[h, token]; RETURN};
ENDCASE => {TokenIO.ReadAgain[h, token]; RETURN};
ENDLOOP;
};
ReadObjectDefinition:
PROC [h: TokenIO.Handle, pushRec:
BOOL ←
FALSE]
RETURNS [obj:
CD.Object←
NIL] = {
index: INT ← -1;
name: Rope.ROPE ← NIL;
versionKey: INT ~ Version[h];
atom: ATOM ← TokenIO.ReadPush[h];
design: CD.Design ~ InlineDesignInReadOperation[h];
class: CD.ObjectClass ← CD.FetchObjectClass[atom, design.technology];
CDSequencer.CheckAborted[design];
IF class=
NIL
OR class.internalRead=
NIL
THEN {
IF atom=NIL THEN {TerminalIO.PutRope["NIL is a bad object class\n"]; RETURN}
ELSE {
n: Rope.ROPE ~ Atom.GetPName[atom];
TerminalIO.PutRopes["object class ", n, " not registered\n"];
CDEnvironment.ExecFileEntry[n, design.technology];
class ← CD.FetchObjectClass[atom, design.technology];
}
};
IF class=
NIL
OR class.internalRead=
NIL
THEN {
TerminalIO.PutF1["reading object class %g failed\n", [atom[atom]]];
TokenIO.Skip[h];
obj ← CDRects.CreateBareRect[[10, 10], CD.errorLayer];
NoteError[h, obj];
RETURN
};
IF versionKey>=15
THEN {
IF class.composed
THEN {
token: TokenIO.Token ← TokenIO.Read[h];
WITH token
SELECT
FROM
r: TokenIO.Token.rope => {
name ← r.value;
index ← TokenIO.ReadInt[h];
};
i: TokenIO.Token.int => index ← i.value;
ENDCASE => TokenIO.EncodingError;
}
ELSE {
token: TokenIO.Token ← TokenIO.Read[h];
WITH token
SELECT
FROM
atom: TokenIO.Token.atom =>
IF atom.value=$CDIOUseDir
THEN {
name ← TokenIO.ReadRope[h];
index ← TokenIO.ReadInt[h]
}
ELSE IF atom.value=$CDIOUseTable THEN index ← TokenIO.ReadInt[h]
ELSE TokenIO.ReadAgain[h, token];
ENDCASE => TokenIO.ReadAgain[h, token];
};
};
obj ← class.internalRead[h, atom];
IF obj=
NIL
OR obj.class=
NIL
THEN {
obj ← NEW[CD.ObjectRep ← CDRects.CreateRect[[10, 10], CD.errorLayer]^];
};
IF index>0 THEN SetTableEntry[h, index, obj];
IF versionKey<17
AND versionKey>0
THEN {
IF class.composed
THEN {
name ← TokenIO.ReadRope[h];
IF versionKey<=4 THEN [] ← TokenIO.ReadRope[h]; --ignore an old versionkey feature
};
};
BEGIN
token: TokenIO.Token ← TokenIO.Read[h];
WITH token
SELECT
FROM
pop: TokenIO.Token.pop => NULL;
ENDCASE => {
props: CD.PropList;
TokenIO.ReadAgain[h, token];
--read in explicite properties
props ← ReadProperties[h];
--save the properties put on the object by the class, but only if not explicitely read
FOR pl: Properties.PropList ← obj.properties, pl.rest
WHILE pl#
NIL
DO
IF Properties.GetProp[props, pl.first.key]=
NIL
THEN
props ← Properties.PutProp[props, pl.first.key, pl.first.val];
--explicite PutProp is ok since props is not yet available to any forked process
ENDLOOP;
--put back the combined properties
obj.properties ← props;
TokenIO.ReadPop[h];
IF versionKey<8 THEN OldAdjustInterest[h, obj];
};
END;
IF versionKey>=17
THEN {
IF name#
NIL
THEN [] ← CDDirectory.Include[design, obj, name]
ELSE IF obj.class.composed THEN CDDirectory.SetOwner[design, obj];
}
ELSE
--old version-- {
IF obj.class.composed
THEN {
DirectoryOp:
PROC [me:
CD.Object, design:
CD.Design, name: Rope.
ROPE, function: CDDirectory.DirectoryFunction] ~ {
IF me.class.composed
THEN {
dp: CDDirectory.DirectoryProc ← CDDirectory.ObToDirectoryProcs[me].directoryOp;
IF dp#NIL THEN dp[me, design, name, function]
}
};
DirectoryOp[obj, NIL, name, rename];
IF versionKey>=15
THEN {
IF ~CDDirectory.IsIncluded[design, obj]
AND ~pushRec
THEN
[] ← CDDirectory.Include[design, obj, name];
};
}
};
IF obj.layer=CD.errorLayer THEN NoteError[h, obj];
};
ReadObject:
PUBLIC
PROC [h: TokenIO.Handle]
RETURNS [ob:
CD.Object←
NIL] = {
t: TokenIO.Token ~ TokenIO.Read[h];
WITH t
SELECT
FROM
int: TokenIO.Token.int => ob ← GetTableEntry[h, int.value];
push: TokenIO.Token.push => {
TokenIO.ReadAgain[h, t]; ob ← ReadObjectDefinition[h];
};
ENDCASE => SIGNAL TokenIO.EncodingError[];
};
ReadInstance:
PUBLIC
PROC [h: TokenIO.Handle]
RETURNS [inst:
CD.Instance] = {
IF Version[h]<=15 THEN RETURN [OldReadInstance[h]]
ELSE {
location: CD.Position ← ReadPos[h];
orientation: CD.Orientation ← ReadOrientation[h];
properties: CD.PropList ← ReadProperties[h];
ob: CD.Object ← ReadObject[h];
inst ← NEW[CD.InstanceRep ← [trans: [location, orientation], properties: properties, ob: ob]]
}
};
ReadPos:
PUBLIC
PROC [h: TokenIO.Handle]
RETURNS [p:
CD.Position] = {
p.x ← TokenIO.ReadInt[h];
p.y ← TokenIO.ReadInt[h];
};
ReadRect:
PUBLIC
PROC [h: TokenIO.Handle]
RETURNS [r:
CD.Rect] = {
r.x1 ← TokenIO.ReadInt[h];
r.y1 ← TokenIO.ReadInt[h];
r.x2 ← TokenIO.ReadInt[h];
r.y2 ← TokenIO.ReadInt[h];
};
FixePushedNames: PROC [design: CD.Design] = {
FOR pl: LIST OF CD.PushRec ← design.actual, pl.rest WHILE pl#NIL DO
pl.first.desc ←
IF pl.first.mightReplace=NIL THEN "top level"
ELSE CD.Describe[pl.first.mightReplace.ob, pl.first.mightReplace.properties, design, 0]
ENDLOOP;
};
ReadPushRec:
PROC [h: TokenIO.Handle]
RETURNS [pr:
CD.PushRec] = {
dummy: CD.Object;
token: TokenIO.Token ← TokenIO.Read[h];
WITH token
SELECT
FROM
atom: TokenIO.Token.atom => {
IF atom.value=$Nil THEN pr.mightReplace←NIL
ELSE {
--old
TokenIO.ReadAgain[h, token];
pr.mightReplace ← ReadInstance[h];
}
};
ENDCASE =>{
TokenIO.ReadAgain[h, token];
pr.mightReplace ← ReadInstance[h];
};
dummy ← ReadObjectDefinition[h, TRUE];
pr.specific ← NARROW[dummy.specific, CD.CellSpecific];
pr.specific.changed ← TRUE;
IF ~Version[h]<17
THEN {
atom: ATOM ← TokenIO.ReadAtom[h];
pr.specific.changed ← atom=$T;
IF atom=$EndOfDesign
THEN {
TokenIO.ReadAgain[h, [atom[atom]]];
TerminalIO.PutRope["****THIS FILE SHOULD BE CONVERTED AGAIN !!!"];
};
};
ToListMode[pr.specific];
pr.specific.dummyCell ← TRUE;
IF Version[h]<=15
AND Version[h]>=11
THEN {
pr.specific.ir ← ReadRect[h];
};
pr.dummyCell ← CDInstances.NewInst[ob: dummy];
};
ToListMode:
PROC [cp:
CD.CellSpecific] = {
old: CD.InstanceSequence ← cp.sequence;
cp.sequence ← NIL;
IF old#
NIL
THEN
FOR n:
NAT
IN [0..old.length)
DO
cp.contents ← CONS[old[n], cp.contents]
ENDLOOP;
};
ReadLayer:
PUBLIC
PROC [h: TokenIO.Handle]
RETURNS [
CD.Layer] = {
key: ATOM ← TokenIO.ReadAtom[h];
IF Version[h]<=12
THEN {
--The layer keys have changed from ChipNDale 2.2 to ChipNDale 2.3.
SELECT key
FROM
$combined => key ← $undefLayer;
$highLightShade => key ← $shadeLayer;
$highLightError => key ← $errorLayer;
$backGround => key ← $backGround;
ENDCASE => NULL;
};
RETURN [CD.FetchLayer[InlineDesignInReadOperation[h].technology, key]];
};
ReadSubObjects:
PROC [h: TokenIO.Handle] = {
obj: CD.Object;
DO
token: TokenIO.Token ← TokenIO.Read[h];
TokenIO.ReadAgain[h, token];
WITH token
SELECT
FROM
push: TokenIO.Token.push => obj ← ReadObject[h];
int: TokenIO.Token.int => obj ← ReadObject[h];
ENDCASE => EXIT;
ENDLOOP;
};
ReadDesignData:
PROC [h: TokenIO.Handle, design:
CD.Design] = {
versionKey: INT ← Version[h];
index, directoryCount: INT;
obj: CD.Object;
directoryCount ← TokenIO.ReadInt[h];
AllocateTables[h, directoryCount+1];
IF versionKey>=15 THEN ReadSubObjects[h]
ELSE {
FOR n:
INT
IN [1..directoryCount]
DO
index ← TokenIO.ReadInt[h];
obj ← ReadObject[h];
SetTableEntry[h, index, obj];
IF versionKey=0
THEN {
DO
token: TokenIO.Token ← TokenIO.Read[h];
WITH token
SELECT
FROM
rope: TokenIO.Token.rope => {
obx: INT = TokenIO.ReadInt[h];
[] ← CDDirectory.Include[design, GetTableEntry[h, obx], rope.value];
}
ENDCASE => {TokenIO.ReadAgain[h, token]; EXIT};
ENDLOOP
}
ENDLOOP;
};
design.properties ← NEW[CD.PropList←ReadProperties[h]];
--this overwrites an previous $FileVersion property read in the normal (wrong) way
CDProperties.PutDesignProp[design, $FileVersion, CDProperties.GetProp[h.properties, $FileVersion]];
design.actual ← NIL;
DO
token: TokenIO.Token ← TokenIO.Read[h];
WITH token
SELECT
FROM
atom: TokenIO.Token.atom =>
IF atom.value=$Push THEN {design.actual ← CONS[ReadPushRec[h], design.actual]}
ELSE {TokenIO.ReadAgain[h, token]; EXIT};
ENDCASE => {TokenIO.ReadAgain[h, token]; EXIT};
ENDLOOP;
IF versionKey>=17 THEN {
ReadDirectory[design, h];
FixePushedNames[design];
};
IF TokenIO.ReadAtom[h]#$EndOfDesign THEN SIGNAL TokenIO.EncodingError;
};
ReadDirectory: PROC [design: CD.Design, h: TokenIO.Handle] = {
num: INT;
IF TokenIO.ReadAtom[h]#$Directory THEN ERROR TokenIO.EncodingError;
num ← TokenIO.ReadInt[h];
FOR i: INT IN [0..num) DO
name: Rope.ROPE ← TokenIO.ReadRope[h];
ob: CD.Object ← ReadObject[h];
IF ob#NIL THEN [] ← CDDirectory.Include[design, ob, name, TRUE];
ENDLOOP;
};
GetFile:
PROC [from:
REF←
NIL, wDir: Rope.
ROPE ←
NIL]
RETURNS [stream:
IO.
STREAM←
NIL, iDidTheOpen:
BOOL ←
FALSE] = {
ReadName:
PROC [wDir: Rope.
ROPE]
RETURNS [name: Rope.
ROPE] = {
IF Rope.IsEmpty[wDir]
THEN TerminalIO.PutRope[" input file"]
ELSE TerminalIO.PutRopes[" input file (", wDir, ")"];
name ← TerminalIO.RequestRope[" > "];
};
nameAsSpecified, nameAsFound: Rope.ROPE←NIL;
IF from#
NIL
AND
ISTYPE[from,
IO.
STREAM]
THEN {
RETURN [NARROW[from, IO.STREAM], FALSE];
};
IF from=NIL THEN nameAsSpecified ← ReadName[wDir]
ELSE
IF
ISTYPE[from, Rope.
ROPE]
THEN {
nameAsSpecified ← NARROW[from, Rope.ROPE];
IF Rope.IsEmpty[nameAsSpecified]
THEN
nameAsSpecified ← ReadName[(IF wDir#NIL THEN wDir ELSE FileNames.CurrentWorkingDirectory[])];
}
ELSE {
TerminalIO.PutRope["ReadDesign: bad parameter\n"]; GOTO NotOpened
};
nameAsFound ← CDEnvironment.FindFile[nameAsSpecified, ".dale", wDir];
IF Rope.IsEmpty[nameAsFound]
THEN {
TerminalIO.PutRopes[nameAsSpecified, " not found\n"]; GOTO NotOpened;
};
stream ←
FS.StreamOpen[nameAsFound, $read,
FS.binaryStreamOptions !
FS.Error =>
IF error.group # bug
THEN {
TerminalIO.PutF["%g not opened: %g\n", [rope[nameAsFound]], [rope[error.explanation]]];
GOTO NotOpened;
}];
iDidTheOpen ← TRUE;
TerminalIO.PutRopes[nameAsFound, " opened \n"];
EXITS NotOpened => {}
};
ReadDesign:
PUBLIC
PROC [from:
REF←
NIL, check:
PROC [h: TokenIO.Handle]
RETURNS [
BOOL] ←
NIL, wDir: Rope.
ROPE ←
NIL, stop:
REF
BOOL ←
NIL]
RETURNS [design:
CD.Design←
NIL] = {
wDirUsed: Rope.ROPE ← NIL;
DoInner:
PROC [h: TokenIO.Handle, iDidTheOpen:
BOOL]
RETURNS [design:
CD.Design←
NIL] = {
ENABLE {
TokenIO.EncodingError => {
TerminalIO.PutRope["** TokenIO encoding problem\n"];
REJECT;
};
RuntimeError.
UNCAUGHT => {
TerminalIO.PutRope["** problem while reading; abort or proceed\n"];
REJECT
};
UNWIND => {
TokenIO.Close[h, iDidTheOpen];
};
};
TechnologyCheck:
PROC [h: TokenIO.Handle] = {
--Side-effect: if bad, design is set to NIL
ENABLE UNWIND => design ← NIL;
dont: BOOL ← CDEvents.ProcessEvent[eventRegistration: readEvent, design: design, x: h, listenToDont: TRUE].dont;
IF dont
THEN {
design ← NIL;
TerminalIO.PutRope["**technology rejects read\n"];
}
};
VersionAndSealCheck:
PROC [h: TokenIO.Handle] = {
--ChipNDale check
versionKey: INT;
IF TokenIO.ReadInt[h]#xChipndaleFile
THEN {
TerminalIO.PutRope["File is not a ChipNDale design\n"];
ERROR TokenIO.EncodingError;
};
--version check
versionKey ← TokenIO.ReadInt[h];
IF versionKey<0
THEN {
TerminalIO.PutF["****design was written with a ChipNDale version which was NOT released; dont expect any help if problems occur; [filekey = %g]\n", [integer[versionKey]]];
versionKey ← -versionKey;
};
CDProperties.PutProp[h.properties, $VersionKey, NEW[INT←versionKey]];
IF versionKey#xVersion
THEN {
OldMsg:
PROC [versionKey:
INT, bar:
BOOL←
FALSE, conv:
BOOL←
FALSE, extra: Rope.
ROPE←
NIL] = {
IF bar THEN TerminalIO.PutRope["****\n"];
TerminalIO.PutF1["design was written with old ChipNDale version; filekey = %g\n", [integer[versionKey]]];
IF conv
THEN
TerminalIO.PutRope["please convert all your designs (by reading and subsequent writing)\n"];
IF extra#NIL THEN TerminalIO.PutRope[extra];
IF bar THEN TerminalIO.PutRope["****\n"];
};
h.oldVersion ← TRUE;
IF versionKey>xVersion
THEN {
-- too new
TerminalIO.PutRope["design has newer file format version\n; bringover ChipNDale !!\n"];
ERROR TokenIO.EncodingError;
}
ELSE
IF versionKey
IN [13..xVersion]
THEN {
-- not new but dont tell it
NULL
}
ELSE
IF versionKey
IN [6..xVersion]
THEN {
-- not new but everything ok
OldMsg[versionKey];
}
ELSE
IF versionKey=4
THEN {
-- known problem versions
OldMsg[versionKey, TRUE, TRUE, "check carefully the alignment of cells which have n-well; if you have troubles, try CD18InputToggle and repeat the input\n"];
}
ELSE
IF versionKey=3
THEN {
-- known problem versions
OldMsg[versionKey, TRUE, TRUE, "check carefully the alignment of cells which have n-well\n"];
}
ELSE
IF versionKey
IN [0..xVersion]
THEN {
-- not new but please convert
OldMsg[versionKey, TRUE, TRUE];
}
ELSE {
-- too old
OldMsg[versionKey, TRUE, FALSE, "sorry this version is no more supported\n"];
ERROR TokenIO.EncodingError;
};
};
--seal check
IF versionKey>0
THEN {
SELECT TokenIO.ReadInt[h]
FROM
-1 => {};
-2 => {TerminalIO.PutRope["file is cached; not the truth\n"];
h.truth ← FALSE;
};
ENDCASE => {
TerminalIO.PutRope["**file had not been properly closed\n"];
ERROR TokenIO.EncodingError;
};
};
};
ReadDesignVersion:
PROC [h: TokenIO.Handle, design:
CD.Design] = {
designVersionKey: Rope.ROPE←NIL;
IF Version[h]>=7
THEN
designVersionKey ← TokenIO.ReadRope[h];
IF Rope.IsEmpty[designVersionKey]
THEN
designVersionKey ← Convert.RopeFromTime[from: BasicTime.Now[], end: seconds];
CDProperties.PutDesignProp[design, $FileVersion, designVersionKey];
CDProperties.PutProp[h.properties, $FileVersion, designVersionKey];
};
-- DoInner
VersionAndSealCheck[h];
technologyKey ← TokenIO.ReadAtom[h];
technologyName ← TokenIO.ReadRope[h];
technology ← CDEnvironment.LoadTechnology[technologyKey, technologyName];
IF technology=NIL THEN GOTO Oops;
h.clientData ← design ← CDOps.CreateDesign[technology];
TechnologyCheck[h];
IF design=NIL THEN GOTO Oops;
design.name ← TokenIO.ReadRope[h];
ReadDesignVersion[h, design]; --read before check, fixed again later
IF iDidTheOpen
THEN {
fullFName: Rope.ROPE; created: BasicTime.GMT;
[fullFName, created] ← FileIdentification[stream];
CDValue.Store[boundTo: design, key: $CDxFromFile, value: fullFName];
CDValue.Store[boundTo: design, key: $CDxLastFile, value: fullFName];
SetWorkingDirectory[design, FileNames.Directory[fullFName]];
IF created#BasicTime.nullGMT
THEN
CDValue.Store[boundTo: design, key: $CDxFileCreated, value: NEW[INT←LOOPHOLE[created]]];
IF Rope.IsEmpty[design.name]
THEN {
name: Rope.ROPE ← FileNames.GetShortName[fullFName, TRUE];
name ← Rope.Substr[name, 0, Rope.Index[name, 0, ".dale", FALSE]];
design.name ← name;
};
};
IF check#
NIL
THEN
IF NOT check[h] THEN GOTO Oops;
ReadDesignData[h, design];
EXITS Oops => RETURN [design←NIL];
};
-- begin ReadDesign
stream: IO.STREAM; h: TokenIO.Handle; iDidTheOpen: BOOL;
technology: CD.Technology; technologyKey: ATOM; technologyName: Rope.ROPE;
[stream, iDidTheOpen] ← GetFile[from, wDir];
IF stream=NIL THEN RETURN;
IF stop=NIL THEN stop ← NEW[BOOL←FALSE];
h ← TokenIO.CreateReader[stream: stream, stop: stop !
TokenIO.EncodingError => {
TerminalIO.PutRope["**TokenIO says file not ok; maybe not a ChipNDale file\n"];
GOTO Oops
};
];
design ← DoInner[h, iDidTheOpen];
IF design#
NIL
THEN {
IF CDProperties.GetPRefProp[h.properties, $errorObject]#
NIL
THEN {
TerminalIO.PutRope[" **design includes some error message(s)\n"];
};
[] ← CDEvents.ProcessEvent[eventRegistration: afterInputEvent, design: design, x: h, listenToDont: FALSE];
};
TokenIO.Close[h, iDidTheOpen];
EXITS Oops => RETURN [NIL];
};
FileIdentification:
PROC [s:
IO.
STREAM]
RETURNS [fullFName: Rope.
ROPE ←
NIL, created: BasicTime.
GMT ← BasicTime.nullGMT] = {
file: FS.OpenFile;
file ← FS.OpenFileFromStream[s ! IO.Error => GOTO Oops];
fullFName ← FS.GetName[file! FS.Error => GOTO Oops].fullFName;
fullFName ← FileNames.ConvertToSlashFormat[fullFName];
created ← FS.GetInfo[file! FS.Error => GOTO Oops].created;
EXITS Oops => {fullFName ← NIL; created ← BasicTime.nullGMT}
};
ReadOrientation:
PUBLIC
PROC [h: TokenIO.Handle]
RETURNS [orientation:
CD.Orientation] = {
i: NAT ← TokenIO.ReadInt[h];
IF Version[h]<=3
THEN {
IF i IN [0..15] THEN orientation ← VAL[i/4*2 + i MOD 2]
ELSE SIGNAL TokenIO.EncodingError;
}
ELSE
IF i IN [0..7] THEN orientation ← VAL[i]
ELSE SIGNAL TokenIO.EncodingError
};
MakeName:
PUBLIC
PROC [base: Rope.
ROPE, ext: Rope.
ROPE←
NIL, wDir: Rope.
ROPE←
NIL, modifier: Rope.
ROPE←
NIL]
RETURNS [Rope.
ROPE] = {
RETURN [CDEnvironment.MakeName[base, ext, wDir, modifier]];
};
SetWorkingDirectory:
PUBLIC
PROC [design:
REF, wDir: Rope.
ROPE] = {
CDEnvironment.SetWorkingDirectory[design, wDir];
};
GetWorkingDirectory:
PUBLIC
PROC [design:
REF]
RETURNS [wDir: Rope.
ROPE←
NIL] = {
RETURN [CDEnvironment.GetWorkingDirectory[design]];
};
MakeShortName:
PUBLIC
PROC [design:
CD.Design]
RETURNS [name: Rope.
ROPE ←
NIL] = {
Translator:
PROC [old:
CHAR]
RETURNS [new:
CHAR] = {
SELECT
TRUE
FROM
old IN ['0..'9] => RETURN [old];
old IN ['a..'z] => RETURN [old];
old IN ['A..'Z] => RETURN [old];
ENDCASE => RETURN ['x];
};
name ← Rope.Translate[base: CD.DesignName[design], translator: Translator];
};
InlineDesignInReadOperation:
PUBLIC
PROC [h: TokenIO.Handle]
RETURNS [
CD.Design] =
INLINE {
RETURN [NARROW[h.clientData]]
};
VersionKey:
PUBLIC
PROC [h: TokenIO.Handle]
RETURNS [
INT] = {
WITH CDProperties.GetProp[h.properties, $VersionKey]
SELECT
FROM
i: REF INT => RETURN [i^];
ENDCASE => RETURN [0];
};
--================================================================
-- old stuff
setManually: INT ← 0; --used for saving old designs
specialForVersion4: BOOL ← FALSE;
FitObjectO:
PROC [ob:
CD.Object, location:
CD.Position ← [0, 0], orientation:
CD.Orientation ←
CD.Orientation[original]]
RETURNS [trans:
CD.Transformation] = {
trans.orient ← orientation;
trans.off ← CDBasics.SubPoints[location, CDBasics.BaseOfRect[CDBasics.MapRect[ob.bbox, [[0, 0], orientation]]]];
};
OldReadInstance:
PROC [h: TokenIO.Handle]
RETURNS [inst:
CD.Instance] = {
location: CD.Position ← ReadPos[h];
orientation: CD.Orientation ← CDIO.ReadOrientation[h];
properties: CD.PropList ← ReadProperties[h];
ob: CD.Object ← ReadObject[h];
versionKey: INT ~ Version[h];
IF versionKey>=8
THEN {
inst ← NEW[CD.InstanceRep ← [trans: FitObject23[ob, location, orientation, h], properties: properties, ob: ob]]
}
ELSE {
IF versionKey>=5
THEN {
??? better instead of I: CDOldInterestRects.InsideRect[ob]
inst ← NEW[CD.InstanceRep ← [trans: CDOps.FitObjectI[ob, location, orientation], properties: properties, ob: ob]]
}
ELSE {
--ancient cases
absoluteMode: BOOL ← TRUE;
IF versionKey<3 THEN absoluteMode←TRUE
ELSE
IF versionKey=4
THEN {
IF specialForVersion4
THEN
IF ob.class.composed THEN absoluteMode←TRUE ELSE absoluteMode←FALSE
ELSE absoluteMode←FALSE
}
ELSE
IF versionKey=3
THEN {
IF ob.class.composed THEN absoluteMode←TRUE ELSE absoluteMode←FALSE
};
IF setManually=1 THEN absoluteMode←TRUE
ELSE IF setManually=2 THEN absoluteMode←FALSE
ELSE IF setManually=3 THEN absoluteMode←ob.class.composed;
IF absoluteMode
THEN
inst ← NEW[CD.InstanceRep ← [trans: FitObjectO[ob, location, orientation], properties: properties, ob: ob]]
ELSE
inst ← NEW[CD.InstanceRep ← [trans: CDOps.FitObjectI[ob, location, orientation], properties: properties, ob: ob]]
};
};
};
Get23Table:
PROC [h: TokenIO.Handle]
RETURNS [RefTab.Ref←
NIL] = {
rt: RefTab.Ref;
WITH Properties.GetProp[h.properties^, $convert23]
SELECT
FROM
tab: RefTab.Ref => rt ← tab;
ENDCASE => {
rt ← RefTab.Create[201];
h.properties^ ← Properties.PutProp[h.properties^, $convert23, rt]
};
RETURN [rt];
};
BBox23:
PROC [ob:
CD.Object, h: TokenIO.Handle]
RETURNS [bbox:
CD.Rect] = {
bbox←ob.bbox;
IF ob.class.composed
THEN
WITH RefTab.Fetch[Get23Table[h], ob].val
SELECT
FROM
rr: REF CD.Rect => RETURN [rr^]
ENDCASE => NULL;
};
FitObject23:
PROC [ob:
CD.Object, location:
CD.Position ← [0, 0], orientation:
CD.Orientation ←
CD.Orientation[original], h: TokenIO.Handle]
RETURNS [trans:
CD.Transformation] = {
--for the conversion from cd2.3 to cd2.4 use bbox with interest rect excluded
oldR: CD.Rect ← ob.bbox;
IF CDCells.IsCell[ob] THEN oldR ← BBox23[ob, h];
trans.orient ← orientation;
trans.off ← CDBasics.SubPoints[location, CDBasics.BaseOfRect[CDBasics.MapRect[oldR, [[0, 0], orientation]]]];
};
OldCD18Input: Commander.CommandProc = {
--fix an old old problem
specialForVersion4 ← ~specialForVersion4;
IF specialForVersion4
THEN
cmd.out.PutRope["Fileformat: switch to first versions of cd18\n"]
ELSE
cmd.out.PutRope["Fileformat: switch to last versions of cd18\n"];
};
OldAdjustInterest:
PROC [h: TokenIO.Handle, ob:
CD.Object] = {
OldSetInterest:
PROC [ob:
CD.Object, r:
CD.Rect] = {
WITH ob.specific
SELECT
FROM
s: CDRepetitions.RepSpecific => s.ir ← r;
s: CDImports.ImportSpecific => s.ir ← r;
s: CDRepetitions.RepSpecific => s.ir ← r;
ENDCASE => NULL;
};
IF ob.class.composed
AND
CDIO.VersionKey[h]<8
THEN {
WITH CDProperties.GetObjectProp[from: ob, prop: oldInterestRectProperty]
SELECT
FROM
pp:
REF
CD.Rect => {
IF CDBasics.NonEmpty[pp^] THEN OldSetInterest[ob, pp^];
CDProperties.PutProp[ob, oldInterestRectProperty, NIL];
};
ENDCASE => NULL;
};
};
OldInternalReadOrigin:
PROC [h: TokenIO.Handle, prop:
ATOM]
RETURNS [val:
REF←NIL] = {
[] ← ReadPos[h];
};
OldInternalReadRProperty:
PROC [h: TokenIO.Handle, prop:
ATOM]
RETURNS [val:
REF] = {
val ← NEW[CD.Rect←ReadRect[h]]
};
oldOriginProperty: ATOM = $origin;
oldInterestRectProperty: ATOM = $interestRect;
OldInit:
PROC [] = {
[] ← CDProperties.RegisterProperty[oldInterestRectProperty];
CDProperties.InstallProcs[prop: oldInterestRectProperty,
procs: CDProperties.PropertyProcsRec[
makeCopy: CDProperties.DontCopy,
internalRead: OldInternalReadRProperty,
exclusive: TRUE
]
];
[] ← CDProperties.RegisterProperty[oldOriginProperty];
CDProperties.InstallProcs[prop: oldOriginProperty,
procs: CDProperties.PropertyProcsRec[
makeCopy: CDProperties.DontCopy,
internalRead: OldInternalReadOrigin,
exclusive: TRUE
]
];
CDEnvironment.RegisterCommander["CD18InputToggle", OldCD18Input, "Toggle input mode of old ChipNDale version CD18"];
};
--================================================================
readEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$ReadTechnologyPrivate];
afterInputEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$AfterInput];
OldInit[];
END.
Version history
versionKey 0
versionKey 1:
objects with children carry names
versionKey 2:
versionKey 3: June 15, 1984 3:46:13 pm PDT;
instances 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
probably while lifetime of 4:
properties which are propertylists are automatically included
versionKey 5: December 14, 1984 10:07:59 am PST;
insiderect for cells no more done with properties; key is removed
versionKey 6: February 1, 1985 4:43:29 pm PST;
properties which are layers are automatically included
versionKey 7: March 26, 1985 12:33:22 pm PST;
file versionkey property included
versionKey 8: April 15, 1985 3:26:35 pm PST;
cd-coords base to file again...
cells get origin and interestrect
imports get interestrect
versionKey 9: May 29, 1985 7:51:45 pm PDT;
CD21
versionKey 10: May 29, 1985 7:51:45 pm PDT;
CD22
Atomicobject have the interest rect on the file
versionKey 11: May 29, 1985 7:51:45 pm PDT;
(CD22)
pushed records get the default interest rect
versionKey 12: January 28, 1986 2:23:27 pm PST;
(CD22)
default properties get $DefaultProperty key
versionKey 13: March 11, 1986 4:17:16 pm PST;
(CD23)
cells may have drawBorder field
gbb April 4, 1986 3:19:31 pm PST
The atoms for the keys of the technology independent layers have changed.
changes to: ReadLayer: if versionKey[]<=12 translate atoms.
versionKey 15: June 20, 1986 9:53:19 am PDT;
Global changes
Number of object for object table is now inside object definition
Directory include is performed for all objects in directory, independent of source.
Objects not in directory have special option to be put in table.
versionKey 16: September 11, 1986 11:40:52 am PDT;
CD2.4.
New TokenIO
New object r instead of size
versionKey 17: January 12, 1987 4:02:28 pm PST
CD2.5.
Directory is treated differently
versionKey 18: April 20, 1987 9:08:40 pm PDT
Atomic objects write actual rectangles