<> <> <> <> <> <> <<>> DIRECTORY Atom, BasicTime, Commander, CD, CDCells, CDBasics, CDDirectory, CDEvents, CDInstances, CDIO, CDOps USING [CreateDesign], CDOrient, CDPrivate, CDProperties, CDRects, CDValue, CommandTool, Convert, FileNames, FS, IO, List, PropertyLists, ProcessProps, Rope, RuntimeError USING [UNCAUGHT], TerminalIO, TokenIO, CDOldInterestRects, UserProfile; CDIn: CEDAR MONITOR IMPORTS Atom, BasicTime, Commander, Convert, CD, CDBasics, CDCells, CDDirectory, CDEvents, CDInstances, CDIO, CDOps, CDOrient, CDPrivate, CDProperties, CDRects, CDValue, CommandTool, FileNames, FS, IO, List, PropertyLists, ProcessProps, Rope, RuntimeError, TerminalIO, TokenIO, UserProfile, CDOldInterestRects EXPORTS CDIO SHARES CD, CDDirectory, CDOldInterestRects = BEGIN <<>> <<--RELEASE: search for the string "RELEASE">> xChipndaleFile: INT = 12121983; xVersion: INT = 13; <<-- global vars>> versionKey: PUBLIC INT; designInReadOperation: PUBLIC CD.Design _ NIL; designVersionKey: Rope.ROPE _ NIL; binfile: IO.STREAM; IndexTable: TYPE = RECORD[table: SEQUENCE max: CARDINAL OF CD.Object]; 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.Object] = INLINE BEGIN 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; signalOnPropertyProblem: BOOL _ TRUE; --set variable with debugger ReadProperties: PUBLIC PROC [] RETURNS [props: CD.PropList_NIL] = BEGIN PropertyProblem: PROC [skip: BOOL_FALSE] = { TerminalIO.WriteRope["**** property not readable"]; IF key#NIL THEN { TerminalIO.WriteRopes["; probably ", Atom.GetPName[key]]; }; TerminalIO.WriteLn[]; IF signalOnPropertyProblem THEN SIGNAL TokenIO.EncodingError; IF skip THEN SkipThrough; }; key: ATOM; propProcs: CDProperties.PropertyProcs; token: TokenIO.Token; DO token _ TokenIO.ReadToken[]; SELECT token.ref FROM $Property => { --with a write proc key _ TokenIO.ReadPushFlag[]; propProcs _ CDProperties.FetchProcs[key]; IF propProcs#NIL AND propProcs.internalRead#NIL THEN { props _ PropertyLists.PutProp[propList: props, prop: key, val: propProcs.internalRead[key]]; } ELSE IF versionKey>=12 THEN { n: Rope.ROPE _ Atom.GetPName[key]; TerminalIO.WriteRopes["**** property ", n, " not registered\n"]; LoadEntry[n, designInReadOperation.technology]; propProcs _ CDProperties.FetchProcs[key]; IF propProcs#NIL AND propProcs.internalRead#NIL THEN { props _ PropertyLists.PutProp[propList: props, prop: key, val: propProcs.internalRead[key]]; } ELSE { TerminalIO.WriteRope["failed"]; IF signalOnPropertyProblem THEN SIGNAL TokenIO.EncodingError; }; } ELSE { token _ TokenIO.ReadToken[]; IF token.kind=rope OR token.kind=atom OR token.kind=int THEN props _ PropertyLists.PutProp[propList: props, prop: key, val: token.ref] ELSE IF token.kind=popFlag THEN { TokenIO.ReadAgain[]; props _ PropertyLists.PutProp[propList: props, prop: key, val: key] } ELSE IF token.kind=pushFlag THEN { IF token.ref=NIL OR token.ref=$properties THEN { propertieProps: CD.PropList _ ReadProperties[]; props _ PropertyLists.PutProp[propList: props, prop: key, val: propertieProps]; } ELSE IF token.ref=$layer THEN { lev: CD.Layer _ ReadLayer[]; props _ PropertyLists.PutProp[propList: props, prop: key, val: CDPrivate.layers[lev]] } ELSE PropertyProblem[skip: FALSE]; token _ TokenIO.ReadToken[]; IF token.kind#popFlag THEN PropertyProblem[skip: TRUE] } ELSE PropertyProblem[] }; token _ TokenIO.ReadToken[]; IF token.kind#popFlag THEN PropertyProblem[skip: TRUE]; }; $DefaultProperty => { token _ TokenIO.ReadToken[]; key _ NARROW[token.ref]; propProcs _ CDProperties.FetchProcs[key]; IF propProcs#NIL AND propProcs.internalRead#NIL THEN { TerminalIO.WriteRope["**** property registered and not readable"]; PropertyProblem[]; }; IF token.kind=rope OR token.kind=atom OR token.kind=int THEN { token _ TokenIO.ReadToken[]; IF token.kind=rope OR token.kind=atom OR token.kind=int THEN props _ PropertyLists.PutProp[propList: props, prop: key, val: token.ref] ELSE PropertyProblem[]; } ELSE IF token.kind=pushFlag THEN { kind: ATOM _ TokenIO.ReadAtom[]; IF kind=$properties THEN { propertieProps: CD.PropList _ ReadProperties[]; props _ PropertyLists.PutProp[propList: props, prop: key, val: propertieProps]; } ELSE IF kind=$layer THEN { lev: CD.Layer _ ReadLayer[]; props _ PropertyLists.PutProp[propList: props, prop: key, val: CDPrivate.layers[lev]] } ELSE IF kind=$ropeList THEN { rList: LIST OF Rope.ROPE _ NIL; token _ TokenIO.ReadToken[]; WHILE token.kind=rope DO rList _ CONS[NARROW[token.ref, Rope.ROPE], rList]; token _ TokenIO.ReadToken[]; ENDLOOP; TokenIO.ReadAgain[]; props _ PropertyLists.PutProp[propList: props, prop: key, val: rList] } ELSE PropertyProblem[skip: FALSE]; token _ TokenIO.ReadToken[]; IF token.kind#popFlag THEN PropertyProblem[skip: TRUE] } ELSE PropertyProblem[] }; ENDCASE => { TokenIO.ReadAgain[]; RETURN [props]; }; ENDLOOP; END; SkipThrough: PROC [] = BEGIN token: TokenIO.Token; layer: INT _ 0; DO token _ TokenIO.ReadToken[]; IF token.kind=pushFlag THEN layer _ layer+1 ELSE IF token.kind=popFlag THEN layer _ layer-1; IF layer<0 THEN EXIT; ENDLOOP; END; SetName: PROC[me: CD.Object, r: Rope.ROPE] ~ INLINE { IF me.class.inDirectory THEN CDDirectory.ObToDirectoryProcs[me].setName[me, r] }; ReadObjectDefinition: PROC [] RETURNS [obj: CD.Object_NIL] = BEGIN token: TokenIO.Token; atom: ATOM = TokenIO.ReadPushFlag[]; class: CD.ObjectClass _ CD.FetchObjectClass[atom, designInReadOperation.technology]; IF class=NIL OR class.internalRead=NIL THEN { n: Rope.ROPE _ Atom.GetPName[atom]; TerminalIO.WriteRopes["object class ", n, " not registered\n"]; LoadEntry[n, designInReadOperation.technology]; class _ CD.FetchObjectClass[atom, designInReadOperation.technology]; }; IF class=NIL OR class.internalRead=NIL THEN { TerminalIO.WriteRopes["reading object class", Atom.GetPName[atom], " failed\n"]; SkipThrough[]; obj _ CDRects.CreateBareRect[[10, 10], CD.errorLayer]; RETURN }; obj _ class.internalRead[]; IF obj=NIL OR obj.class=NIL THEN obj _ NEW[CD.ObjectRep _ CDRects.CreateRect[[10, 10], CD.errorLayer]^]; IF versionKey>0 THEN { IF class.inDirectory THEN { name: Rope.ROPE _ TokenIO.ReadRope[]; SetName[obj, name]; IF versionKey<=4 THEN [] _ TokenIO.ReadRope[]; --ignore an old versionkey feature }; }; token _ TokenIO.ReadToken[]; IF token.kind#popFlag THEN { TokenIO.ReadAgain[]; obj.properties _ ReadProperties[]; TokenIO.ReadPopFlag[]; IF versionKey<8 THEN CDOldInterestRects.AdjustInterest[obj]; <<--border was'nt a very public feature in 12; might be removed>> IF versionKey=12 THEN { IF CDCells.IsCell[obj] AND CDProperties.GetObjectProp[obj, $border]#NIL THEN { CDProperties.PutProp[obj, $border, NIL]; CDCells.SetBorder[obj, TRUE]; } } }; END; ReadObject: PUBLIC PROC [] RETURNS [CD.Object] = BEGIN t: TokenIO.Token = TokenIO.ReadToken[]; IF t.kind=int THEN { -- instance ins: INT _ NARROW[t.ref, REF INT]^; RETURN [GetTableEntry[ins]] }; TokenIO.ReadAgain; RETURN [ReadObjectDefinition[]] END; setManually: INT _ 0; --used for saving old designs specialForVersion4: BOOL _ FALSE; ReadInstance: PUBLIC PROC [] RETURNS [CD.Instance] = BEGIN inst: CD.Instance; location: CD.Position _ ReadPos[]; orientation: CD.Orientation _ CDIO.ReadOrientation[]; properties: CD.PropList _ ReadProperties[]; ob: CD.Object _ ReadObject[]; IF versionKey>=9 THEN --this is the current truth and normal case inst _ NEW[CD.InstanceRep _ [ location: location, orientation: orientation, properties: properties, ob: ob ]] ELSE { OldNewInstIX: PROC [ob: CD.Object_NIL, location: CD.Position_[0,0], orientation: CD.Orientation_0, selected: BOOLEAN _ FALSE, properties: CD.PropList_NIL] RETURNS [CD.Instance] = BEGIN off: CD.Position = CDBasics.BaseOfRect[ CDOrient.MapRect[ itemInCell: CDOldInterestRects.InsideRect[ob], cellSize: ob.size, cellInstOrient: orientation, cellInstPos: [0, 0] ]]; a: CD.Instance = NEW[CD.InstanceRep _ CD.InstanceRep[ ob: ob, location: CDBasics.SubPoints[location, off], orientation: orientation, selected: selected, properties: properties ]]; RETURN [a] END; IF versionKey>=8 THEN inst _ NEW[CD.InstanceRep _ [ location: location, orientation: orientation, properties: properties, ob: ob ]] ELSE IF versionKey>=5 THEN inst _ OldNewInstIX[ob: ob, location: location, orientation: orientation, properties: properties] ELSE { --ancient cases absoluteMode: BOOL _ TRUE; IF versionKey<3 THEN absoluteMode_TRUE ELSE IF versionKey=4 THEN { IF specialForVersion4 THEN IF ob.class.inDirectory THEN absoluteMode_TRUE ELSE absoluteMode_FALSE ELSE absoluteMode_FALSE } ELSE IF versionKey=3 THEN { IF ob.class.inDirectory 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.inDirectory; IF absoluteMode THEN inst _ NEW[CD.InstanceRep _ [ location: location, orientation: orientation, properties: properties, ob: ob, selected: FALSE]] ELSE inst _ OldNewInstIX[ob: ob, location: location, orientation: orientation, properties: properties]; }; }; RETURN [inst]; END; ReadInstanceList: PUBLIC PROC [] RETURNS [list: CD.InstanceList_NIL] = BEGIN num: INT = TokenIO.ReadInt[]; THROUGH [0..num) DO list _ CONS[ReadInstance[], list]; ENDLOOP END; ReadPos: PUBLIC PROC [] RETURNS [p: CD.Position] = BEGIN p.x _ TokenIO.ReadInt[]; p.y _ TokenIO.ReadInt[]; END; ReadRect: PUBLIC PROC [] RETURNS [r: CD.Rect] = BEGIN r.x1 _ TokenIO.ReadInt[]; r.y1 _ TokenIO.ReadInt[]; r.x2 _ TokenIO.ReadInt[]; r.y2 _ TokenIO.ReadInt[]; END; ReadPushRec: PROC [] RETURNS [pr: CD.PushRec] = BEGIN token: TokenIO.Token _ TokenIO.ReadToken[]; dummy: CD.Object; IF token.ref=$Nil THEN pr.mightReplace_NIL ELSE { TokenIO.ReadAgain[]; pr.mightReplace _ ReadInstance[]; }; dummy _ ReadObjectDefinition[]; pr.changed _ pr.indirectlyChanged _ TRUE; pr.specific _ NARROW[dummy.specificRef, CD.CellPtr]; IF versionKey>=11 THEN { pr.specific.dIr _ ReadRect[]; IF pr.specific.useDIr THEN pr.specific.ir _ pr.specific.dIr; }; pr.dummyCell _ CDInstances.NewInst[ob: dummy]; END; ReadLayer: PUBLIC PROC [] RETURNS [CD.Layer] = BEGIN key: ATOM _ TokenIO.ReadAtom[]; <> IF CDIO.VersionKey[]<=12 THEN -- New layer keys for CD 2.3 SELECT key FROM $combined => key _ $undefLayer; $highLightShade => key _ $shadeLayer; $highLightError => key _ $errorLayer; $backGround => key _ $backGround; ENDCASE => NULL; RETURN [CD.FetchLayer[designInReadOperation.technology, key]]; END; IsOwner: PROC [ob: CD.Object, d: CD.Design] RETURNS [BOOL] = { x: REF ~ (IF d=NIL THEN NIL ELSE d.reserved); RETURN [ CDProperties.GetObjectProp[ob, $OwnerDesign]=x ]; }; ReadDesignData: PROC [] = BEGIN index, directoryCount: INT; token: TokenIO.Token; obj: CD.Object; directoryCount _ TokenIO.ReadInt[]; AllocateTables[directoryCount+1]; FOR n: INT IN [1..directoryCount] DO index _ TokenIO.ReadInt[]; obj _ ReadObject[]; 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.class.inDirectory THEN { <<--hack to simplify some read procedures... >> IF ~IsOwner[obj, designInReadOperation] THEN { name: Rope.ROPE = CDDirectory.Name[obj]; [] _ CDDirectory.Include[designInReadOperation, obj, name]; } } ENDLOOP; designInReadOperation.properties _ NEW[CD.PropList_ReadProperties[]]; <<--this overwrites an previous $FileVersion property read in the normal (wrong) way>> CDProperties.PutDesignProp[designInReadOperation, $FileVersion, designVersionKey]; 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 SIGNAL TokenIO.EncodingError; END; ReadDesign: PUBLIC ENTRY PROC [from: REF_NIL, check: PROC [CD.Design] RETURNS [BOOL] _ NIL, wDir: Rope.ROPE _ 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 { UNWIND => designInReadOperation _ NIL; TokenIO.EncodingError => { TerminalIO.WriteRope["** TokenIO encoding problem\n"]; REJECT; }; RuntimeError.UNCAUGHT => { TerminalIO.WriteRope["** problem while reading; abort or proceed\n"]; REJECT }; }; 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 [10..xVersion] THEN { -- not new but dont tell it NULL } ELSE IF versionKey IN [5..xVersion] THEN { -- not new but everything ok TerminalIO.WriteRope["design was written with older chipndaleversion\n"]; } ELSE IF versionKey=4 THEN { -- known problem versions TerminalIO.WriteRope["********\n"]; TerminalIO.WriteRope["design was written with older chipndaleversion; filekey = 4\n"]; TerminalIO.WriteRope["Please convert also your other designs (by reading and subsequent writing)\n"]; TerminalIO.WriteRope["Check carefully the alignment of cells which have n-well\n"]; TerminalIO.WriteRope[" IF alignment is wrong THEN { try with a commandtool:\n"]; TerminalIO.WriteRope[" CD18InputToggle\n"]; TerminalIO.WriteRope[" }\n"]; TerminalIO.WriteRope["If the design looked bad, call Jacobi.pa, (I might help you, but also I'd like to know about the problem, and, whether the proposed fix helped)\n"]; TerminalIO.WriteRope["********\n"]; } ELSE IF versionKey=3 THEN { -- known problem versions TerminalIO.WriteRope["********\n"]; TerminalIO.WriteRope["design was written with older chipndaleversion; filekey = 3\n"]; TerminalIO.WriteRope["Please convert also your other designs (by reading and subsequent writing)\n"]; TerminalIO.WriteRope["Check carefully the alignment of cells which have n-well"]; TerminalIO.WriteRope["If the design looked bad, call Jacobi.pa, (I might help you, but also I'd like to know about the problem)\n"]; TerminalIO.WriteRope["********\n"]; } ELSE IF versionKey IN [0..xVersion] THEN { -- not new but please convert TerminalIO.WriteRope["********\n"]; TerminalIO.WriteRope["Design was written with older chipndaleversion\n"]; TerminalIO.WriteRope["Please convert also your other designs (by reading and subsequent writing)\n"]; TerminalIO.WriteRope["********\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; ReadVersionKeys: PROC [design: CD.Design] = BEGIN IF versionKey>=7 THEN { designVersionKey _ TokenIO.ReadRope[]; }; IF Rope.IsEmpty[designVersionKey] THEN designVersionKey _ Convert.RopeFromTime[from: BasicTime.Now[], end: seconds]; CDProperties.PutDesignProp[design, $FileVersion, designVersionKey]; END; ReadDesignName: PROC [] RETURNS [name: Rope.ROPE] = BEGIN name _ TokenIO.ReadRope[]; IF Rope.IsEmpty[name] THEN { name _ FileNames.GetShortName[fileName, TRUE]; name _ Rope.Substr[name, 0, Rope.Index[name, 0, ".dale", FALSE]] } END; <<-- DoWhileAttached>> VersionAndSealCheck[]; technologyKey _ TokenIO.ReadAtom[]; technologyName _ TokenIO.ReadRope[]; technology _ CD.FetchTechnology[technologyKey]; IF technology=NIL THEN { TerminalIO.WriteRopes["technology '", technologyName, "' not loaded\n"]; GOTO NotDoneAndRelease }; designInReadOperation _ CDOps.CreateDesign[technology]; TechnologyCheck[]; IF designInReadOperation=NIL THEN GOTO NotDoneAndRelease; designInReadOperation.name _ ReadDesignName[]; ReadVersionKeys[designInReadOperation]; --read before check, fixed again later IF check#NIL THEN { IF NOT check[designInReadOperation] THEN GOTO NotDoneAndRelease; }; ReadDesignData[]; CDValue.Store[boundTo: designInReadOperation, key: $CDxFromFile, value: fileName]; CDValue.Store[boundTo: designInReadOperation, key: $CDxLastFile, value: fileName]; TokenIO.ReleaseReader[]; 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.WriteRopes[r, "... not attached\n"]; GOTO NotAttached } ]; DoWhileAttached[]; EXITS NotAttached => RETURN END; <<-- begin ReadDesign>> iDidTheOpen: BOOL _ FALSE; name: Rope.ROPE; <<>> <<-- open file; assign fileName and binfile>> IF wDir=NIL THEN wDir _ FileNames.CurrentWorkingDirectory[]; IF from#NIL AND ISTYPE[from, IO.STREAM] THEN { fileName _ NIL; binfile _ NARROW[from, IO.STREAM] } ELSE { ReadName: PROC [wDir: Rope.ROPE] RETURNS [name: Rope.ROPE] = { TerminalIO.WriteRope[Rope.Cat[" input file (", wDir, ")"]]; name _ TerminalIO.RequestRope[" > "]; }; IF from=NIL THEN name _ ReadName[wDir] ELSE IF ISTYPE[from, Rope.ROPE] THEN { name _ NARROW[from, Rope.ROPE]; IF Rope.IsEmpty[name] THEN name _ ReadName[wDir]; } ELSE { TerminalIO.WriteRope["ReadDesign does not support type of 'from' parameter\n"]; GOTO NotOpened; }; fileName _ MakeName[name, "dale", wDir]; binfile _ FS.StreamOpen[fileName ! FS.Error => IF error.group # bug THEN { TerminalIO.WriteRope[Rope.Cat[fileName, " not opened: ", error.explanation, "\n"]]; GOTO NotOpened; }]; iDidTheOpen _ TRUE; TerminalIO.WriteRope[Rope.Cat[fileName, " opened \n"]]; }; <<-- do the actual work>> DoReadDesign[check]; design _ designInReadOperation; <<-- finalize>> designInReadOperation _ NIL; indexTable _ NIL; tableTable _ NIL; IF iDidTheOpen THEN IO.Close[binfile]; [] _ CDEvents.ProcessEvent[ev: afterInputEvent, design: design, x: NIL, listenToDont: FALSE]; 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 SIGNAL TokenIO.EncodingError; } ELSE IF i IN [0..7] THEN orientation _ i ELSE SIGNAL 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; wDirAtStart: Rope.ROPE = FileNames.CurrentWorkingDirectory[]; GetWorkingDirectory: PUBLIC PROC [design: REF] RETURNS [wDir: Rope.ROPE_NIL] = BEGIN WITH design SELECT FROM des: CD.Design => { WITH CDValue.Fetch[boundTo: design, key: $WorkingDirectory, propagation: global] SELECT FROM r: Rope.ROPE => wDir _ CheckWorkingDirectory[r]; ENDCASE => NULL; }; tech: CD.Technology => { techName: Rope.ROPE _ tech.name; IF techName=NIL THEN techName _ Atom.GetPName[tech.key]; wDir _ CheckWorkingDirectory[UserProfile.Token[ key: Rope.Cat["ChipNDale.", techName, ".BaseDirectory"], default: NIL ]]; IF wDir=NIL THEN wDir _ GetWorkingDirectory[NIL]; IF wDir=NIL THEN wDir _ wDirAtStart; }; ENDCASE => { IF design=NIL THEN { wDir _ CheckWorkingDirectory[ UserProfile.Token[key: "ChipNDale.BaseDirectory", default: NIL]]; IF wDir=NIL THEN wDir _ wDirAtStart; }; }; END; SetProcessWDir: PROC [wDir: Rope.ROPE] = { [] _ List.PutAssoc[key: $WorkingDirectory, val: wDir, aList: ProcessProps.GetPropList[]]; }; 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 SetProcessWDir[wDir] ELSE wDir _ 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.ROPE_NIL, wDir: Rope.ROPE_NIL, modifier: Rope.ROPE_NIL] RETURNS [Rope.ROPE] = BEGIN bang: INT = TrailingChar[base, '!]; <<--remove version number>> r: Rope.ROPE _ base.Substr[len: bang]; <<--include modifier>> IF ~modifier.IsEmpty[] THEN r _ r.Concat[modifier]; <<--include extension>> IF ~ext.IsEmpty[] AND (TrailingChar[r, '.]>=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> len: INT _ Rope.Length[base]; pos: INT _ len; WHILE pos > 0 DO SELECT Rope.Fetch[base, pos _ pos - 1] FROM '. => RETURN [pos]; '!, '], '>, '/ => EXIT; ENDCASE; ENDLOOP; RETURN [len]; }; SuggestedModule: PROC [base: Rope.ROPE] RETURNS [Rope.ROPE] = { <<--given a filename, suggests a modulename>> len, dot: INT; base _ FileNames.GetShortName[base]; len _ Rope.Length[base]; dot _ TrailingDot[base]; IF len>dot AND Rope.Equal[Rope.Substr[base, dot+1], "dale", FALSE] THEN base _ Rope.Substr[base, 0, dot]; RETURN [base] }; <<--MakeShortName>> WITH CDValue.Fetch[boundTo: design, key: $CDxFromFile] SELECT FROM r: Rope.ROPE => name _ SuggestedModule[r]; ENDCASE => NULL; IF name=NIL THEN name _ design.name; IF name=NIL THEN name _ "noname" END; NewDesignHasBeenCreated: CDEvents.EventProc = <<-- PROC [event: REF, design: CD.Design, x: REF] -- >> <<--repaint captions and sometimes the contents>> BEGIN SetWorkingDirectory[design, FileNames.CurrentWorkingDirectory[]]; END; <<>> CD18Input: Commander.CommandProc = BEGIN specialForVersion4 _ ~specialForVersion4; IF specialForVersion4 THEN cmd.out.PutRope["Fileformat: switch to old version of cd18\n"] ELSE cmd.out.PutRope["Fileformat: switch to last version of cd18\n"]; END; <<-- Loader ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> GetEntry: PROC [fileName: Rope.ROPE, key: Rope.ROPE] RETURNS [entry: Rope.ROPE_NIL] = BEGIN found: BOOL _ FALSE; OneLine: PROC [line: Rope.ROPE, key: Rope.ROPE] = { stream: IO.STREAM _ IO.RIS[line]; keyFound: Rope.ROPE _ IO.GetID[stream]; IF Rope.Equal[keyFound, key] THEN { found _ TRUE; [] _ IO.SkipWhitespace[stream]; entry _ IO.GetLineRope[stream]; } }; file: IO.STREAM _ FS.StreamOpen[fileName ! FS.Error => GOTO thatsIt]; WHILE ~found DO line: Rope.ROPE _ IO.GetLineRope[file ! IO.EndOfStream => GOTO thatsIt]; IF ~Rope.IsEmpty[line] THEN OneLine[line, key ! IO.EndOfStream => GOTO thatsIt; IO.Error => { TerminalIO.WriteF["**error reading entry file: %g line: %g\n", [rope[fileName]], [rope[line]]]; CONTINUE }; ]; ENDLOOP; EXITS thatsIt => NULL; END; LoadEntry: PROC [key: Rope.ROPE, technology: CD.Technology_NIL, modifier: Rope.ROPE_NIL] = BEGIN wDir, entry, oldWDir, out: Rope.ROPE; Fetch: PROC [mod: Rope.ROPE] = { IF modifier#NIL THEN mod _ Rope.Cat[mod, "-", modifier]; mod _ CDIO.MakeName["ChipNDale-", "CDLoadList", wDir, mod]; entry _ GetEntry[mod, key]; }; searchPath: LIST OF Rope.ROPE _ LIST[CDIO.GetWorkingDirectory[NIL], "///Commands/"]; IF technology#NIL THEN { wDir _ CDIO.GetWorkingDirectory[technology]; searchPath _ CONS[wDir, searchPath]; Fetch[technology.name]; }; IF entry=NIL THEN { wDir _ CDIO.GetWorkingDirectory[NIL]; Fetch["CD"]; }; IF entry=NIL THEN TerminalIO.WriteRopes["command line for ", key, " not found\n"] ELSE { cmd: Commander.Handle _ NEW[Commander.CommandObject _ [ out: TerminalIO.TOS[], err: TerminalIO.TOS[], in: IO.noInputStream, propertyList: List.PutAssoc[key: $SearchRules, val: searchPath, aList: NIL] ]]; oldWDir _ FileNames.CurrentWorkingDirectory[]; SetProcessWDir[wDir]; TerminalIO.WriteRopes["tries to execute: ", entry, "\n"]; out _ CommandTool.DoCommandRope[commandLine: entry, parent: cmd].out; TerminalIO.WriteRopes["\n{", out, "}\n"]; SetProcessWDir[oldWDir]; }; END; <<>> <<>> <<-- Module Initialization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> readEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$ReadTechnologyPrivate]; afterInputEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$AfterInput]; CDValue.RegisterKey[key: $WorkingDirectory]; CDEvents.RegisterEventProc[$CreateNewDesign, NewDesignHasBeenCreated]; <<--fix a problem in CD18>> Commander.Register[ key: "///Commands/CD18InputToggle", proc: CD18Input, doc: "toggle input mode of cd18" ]; <<--hack hack, so I don't have to make an Interface change>> CDProperties.PutAtomProp[$CDIOPrivate, $CDIOPrivate, NEW[PROC[Rope.ROPE, CD.Technology, Rope.ROPE]_LoadEntry]]; END. <> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<(CD22)>> <> <> <<(CD22)>> <> <> <<(CD23)>> <> <> <> <> <<>>