<> <> <> <> <> <<>> DIRECTORY BasicTime, CDIO, CD, CDBasics, CDDirectory, CDEvents, CDExtras, CDOrient, CDPrivate, CDProperties, CDValue, Convert, FileNames, FS, IO, Process, Rope, TerminalIO, TokenIO; CDOut: CEDAR PROGRAM --monitored by TokenIO IMPORTS BasicTime, CD, CDBasics, CDIO, CDDirectory, CDEvents, CDExtras, CDOrient, CDProperties, CDValue, Convert, FileNames, FS, IO, Process, Rope, TerminalIO, TokenIO EXPORTS CDIO SHARES CDProperties = BEGIN xChipndaleFile: INT = 12121983; xVersion: INT = 9; <<-- global variables; are protected by the requirement of attaching Tokenio>> designToWrite: CD.Design; directoryNum: INT; directoryMark: TokenIO.Mark; outputKey: REF _ NEW[INT]; thisTime: REF; lastTime: REF; isQuiet: BOOL; WriteRope: PROC [r: Rope.ROPE] = BEGIN IF ~isQuiet THEN TerminalIO.WriteRope[r] END; WriteLayer: PUBLIC PROC [l: CD.Layer] = BEGIN TokenIO.WriteAtom[CD.LayerKey[l]]; END; WriteProperties: PUBLIC PROC [props: CD.Properties] = BEGIN FOR l: CD.Properties _ props, l.rest WHILE l#NIL DO pp: CDProperties.PropertyProcs; IF NOT ISTYPE[l.first.key, ATOM] THEN LOOP; pp _ CDProperties.FetchProcs[l.first.key]; IF pp#NIL AND pp.internalWrite#NIL THEN { TokenIO.WriteAtom[$Property]; TokenIO.WritePushFlag[NARROW[l.first.key, ATOM]]; pp.internalWrite[l.first.key, l.first.val]; TokenIO.WritePopFlag[]; } ELSE WITH l.first.val SELECT FROM r: Rope.ROPE => { TokenIO.WriteAtom[$Property]; TokenIO.WritePushFlag[NARROW[l.first.key, ATOM]]; TokenIO.WriteRope[r]; TokenIO.WritePopFlag[]; }; at: ATOM => { TokenIO.WriteAtom[$Property]; TokenIO.WritePushFlag[NARROW[l.first.key, ATOM]]; TokenIO.WriteAtom[at]; TokenIO.WritePopFlag[]; }; ri: REF INT => { TokenIO.WriteAtom[$Property]; TokenIO.WritePushFlag[NARROW[l.first.key, ATOM]]; TokenIO.WriteInt[ri^]; TokenIO.WritePopFlag[]; }; pl: CD.Properties => { TokenIO.WriteAtom[$Property]; TokenIO.WritePushFlag[NARROW[l.first.key, ATOM]]; TokenIO.WritePushFlag[NIL]; -- now comes a property list WriteProperties[pl]; TokenIO.WritePopFlag[]; -- end of property list TokenIO.WritePopFlag[]; -- end of this property }; pl: CDPrivate.LayerRef => { TokenIO.WriteAtom[$Property]; TokenIO.WritePushFlag[NARROW[l.first.key, ATOM]]; TokenIO.WritePushFlag[$layer]; -- now comes a property list WriteLayer[pl.number]; TokenIO.WritePopFlag[]; -- undoes pushflag layer TokenIO.WritePopFlag[]; -- end of this property }; ENDCASE => NULL; ENDLOOP; END; ARectIX: PROC [inst: CD.Instance] RETURNS [CD.Rect] = <<--old compatibility stuff>> BEGIN RETURN [ CDOrient.MapRect[ itemInCell: inst.ob.class.oldInsideRect[inst.ob], cellSize: inst.ob.size, cellInstOrient: inst.orientation, cellInstPos: inst.location ] ] END; WriteInstance: PUBLIC PROC [ap: CD.Instance] = BEGIN loc: CD.Position; IF xVersion<=7 AND xVersion>2 THEN loc _ CDBasics.BaseOfRect[ARectIX[ap]] ELSE loc _ ap.location; TokenIO.WriteInt[loc.x]; TokenIO.WriteInt[loc.y]; CDIO.WriteOrientation[ap.orientation]; WriteProperties[ap.properties]; WriteObject[ap.ob]; END; WriteInstanceList: PUBLIC PROC [list: CD.InstanceList] = BEGIN count: INT _ 0; FOR l: CD.InstanceList _ list, l.rest WHILE l#NIL DO count _ count+1; ENDLOOP; TokenIO.WriteInt[count]; FOR l: CD.InstanceList _ list, l.rest WHILE l#NIL DO WriteInstance[l.first]; ENDLOOP; END; WriteObject: PUBLIC PROC [ob: CD.Object] = BEGIN xx: REF = CDProperties.GetPropFromObject[from: ob, prop: thisTime]; IF xx#NIL AND ISTYPE[xx, REF INT] THEN { WriteRope["."]; TokenIO.WriteInt[NARROW[xx, REF INT]^]; RETURN }; WriteRope["x"]; DoWriteObject[ob] END; DoWriteObject: PROC [ob: CD.Object] = BEGIN IF ob.class.internalWrite=NIL THEN { ob1: CD.Object _ CDDirectory.ExpandHard[ob, designToWrite, NIL]; IF ob1#NIL THEN { WriteRope["*"]; WriteObject[ob1]; } ELSE { TokenIO.WritePushFlag[$Unknown]; TokenIO.WritePopFlag[]; WriteRope["*object not written\n"]; }; RETURN }; TokenIO.WritePushFlag[NARROW[ob.class.objectType, ATOM]]; ob.class.internalWrite[ob]; IF ob.class.inDirectory THEN { TokenIO.WriteRope[CDDirectory.Name[ob]]; }; WriteProperties[ob.properties]; CDProperties.PutPropOnObject[onto: ob, prop: lastTime, val: NIL]; TokenIO.WritePopFlag[]; END; WritePushLayer: PROC [pl: LIST OF CD.PushRec] = BEGIN IF pl=NIL THEN RETURN; IF pl.rest#NIL THEN WritePushLayer[pl.rest]; TokenIO.WriteAtom[$Push]; IF pl.first.mightReplace#NIL THEN WriteInstance[pl.first.mightReplace] ELSE TokenIO.WriteAtom[$Nil]; WriteObject[pl.first.dummyCell.ob] END; EachChildren: CDDirectory.EnumerateObjectsProc --PROC [me: Object, x: REF]-- = BEGIN xx: REF = CDProperties.GetPropFromObject[from: me, prop: thisTime]; IF xx#NIL THEN RETURN; -- it and its children are already out IF me.class.inDirectory THEN CDDirectory.EnumerateChildObjects[me: me, p: EachChildren, x: x]; directoryNum _ directoryNum+1; TokenIO.WriteInt[directoryNum]; DoWriteObject[me]; CDProperties.PutPropOnObject[onto: me, prop: thisTime, val: NEW[INT_directoryNum]]; END; EachDirectoryEntry: CDDirectory.EachEntryAction --[name: Rope.ROPE, ob: CD.Object] RETURNS [quit: BOOL_FALSE]-- = BEGIN EachChildren[ob, NIL]; END; DoWriteDesign: PROC [] = BEGIN ENABLE TokenIO.WritingStopped => { RemoveOldProperties[designToWrite, lastTime]; REJECT }; WriteVersionKeys: PROC [design: CD.Design] = BEGIN TokenIO.WriteRope[Convert.RopeFromTime[from: BasicTime.Now[], end: seconds]]; END; thisTime _ NEW[INT]; lastTime _ CDValue.Fetch[boundTo: designToWrite, key: outputKey, propagation: design]; IF lastTime=NIL THEN {lastTime_NEW[INT]}; CDValue.Store[boundTo: designToWrite, key: outputKey, value: thisTime]; directoryNum_0; IF Rope.Length[designToWrite.name]<=0 OR Rope.Fetch[designToWrite.name]='/ OR Rope.Fetch[designToWrite.name]='[ THEN TokenIO.WriteRope[NIL] ELSE TokenIO.WriteRope[designToWrite.name]; WriteVersionKeys[designToWrite]; directoryMark _ TokenIO.MarkAndWriteInt[directoryNum]; -- number of entries in directory [] _ CDDirectory.Enumerate[design: designToWrite, action: EachDirectoryEntry]; WriteProperties[designToWrite.properties]; WritePushLayer[designToWrite.actual]; TokenIO.UpdateMark[mark: directoryMark, value: directoryNum]; TokenIO.WriteAtom[$EndOfDesign]; END; RemoveOldProperties: PROC[design: CD.Design, key: REF] = BEGIN <<--at this place we know that CDExtras will fork and will set the priority down>> CDExtras.RemoveProperties[design, key] END; DontOverWrite: ERROR = CODE; CanNotAttach: SIGNAL = CODE; WriteDesign: PUBLIC PROC [design: CD.Design, to: REF_NIL, quiet: BOOL, emergency: BOOL] RETURNS [done: BOOL_FALSE] = <<--to is either a IO.STREAM, a Rope.ROPE, or NIL>> <<--if emergency, some locks are ignored, interactive input is skipped; you better >> <<--roll back after an emergency write is done>> BEGIN ENABLE DontOverWrite => GOTO NotOpened; DoAttach: PROC [] RETURNS [done: BOOL] = BEGIN DoRealAttach: PROC [] RETURNS [done: BOOL_FALSE] = BEGIN TokenIO.AttachWriter[binFile ! TokenIO.Error => GOTO AttachProblem]; done _ TRUE; EXITS AttachProblem => RETURN END; count: NAT _ 0; done _ DoRealAttach[]; WHILE NOT done AND emergency DO TokenIO.StopWriting[]; Process.Pause[Process.SecondsToTicks[1]]; TokenIO.StopWriting[]; Process.Pause[Process.SecondsToTicks[2]]; count _ count+1; IO.Reset[binFile]; TerminalIO.WriteRope["TRIES TO BREAK THE LOCK\n"]; TokenIO.ReleaseWriter[]; -- XXXXXXX DANGEROUS Process.Pause[Process.SecondsToTicks[1]]; done _ DoRealAttach[]; IF NOT done AND count>5 THEN { count _ 0; SIGNAL CanNotAttach; }; ENDLOOP END; InName: PROC [wDir: Rope.ROPE_NIL] RETURNS [name: Rope.ROPE] = BEGIN CheckExistance: PROC [name: Rope.ROPE] = <<--Errors DontOverWrite if necessary>> BEGIN temfile: IO.STREAM _ FS.StreamOpen[name ! FS.Error => IF error.group#bug THEN GOTO NotFound]; <<--file exists already>> TerminalIO.WriteRope["File "]; TerminalIO.WriteRope[name]; TerminalIO.WriteRope[" exists already; "]; IF ~TerminalIO.UserSaysYes[label: "overwrite? ", text: "overwrite?", default: FALSE] THEN ERROR DontOverWrite; TerminalIO.WriteRope[" yes\n"]; EXITS NotFound => { --this is the "normal" case of an not yet existing file NULL } END; IF Rope.IsEmpty[wDir] THEN wDir _ FileNames.CurrentWorkingDirectory[]; IF emergency THEN name _ "///temp/ChipNDale/emergency/emergency.dale" ELSE { TerminalIO.WriteRope["file name:"]; IF ~Rope.IsEmpty[wDir] THEN { TerminalIO.WriteRope[" ("]; TerminalIO.WriteRope[wDir]; TerminalIO.WriteRope[")"]; }; name _ TerminalIO.RequestRope[" > "]; name _ CDIO.MakeName[name, "dale", wDir]; CheckExistance[name]; } END; Help: PROC [] = BEGIN Write: PROC [r: Rope.ROPE] = { TerminalIO.WriteRope[r]; TerminalIO.WriteLn[]; }; Write["****************************************"]; Write["Help for saving a design:"]; Write["wait until the background saving is done and make a copy of it! (but don't rely on background saving alone; background saving is done WITHOUT requiring monitor locks, for obvious reasons.)"]; Write["then, try regular output again, before you proceed to any of the more drastic methods following:\n"]; Write["SHIFT-SHIFT-SWAT (>2 seconds) should save all designs"]; Write["or use a command tool: (the command tool commands require you to bringover the necesarry sources and bcd's first)"]; Write[" ""_ CDSequencerImpl.savePeriod _ -1"" "]; Write[" prevents any further un-monitored automatic saving in parallel with your other command tool commands."]; Write[" ""_ CDEmergencyHandling.SaveAll[]"" "]; Write[" or"]; Write[" ""_ TokenIO.ReleaseWriter[]"" "]; Write[" to release the locks; after this try a regular output command"]; Write["****************************************"]; END; <<--WriteDesign>> iMadeTheOpen: BOOL_FALSE; binFile: IO.STREAM; sealMark: TokenIO.Mark; name, fileName: Rope.ROPE; wDir: Rope.ROPE _ CDIO.GetWorkingDirectory[design]; IF to#NIL AND ISTYPE[to, IO.STREAM] THEN { binFile _ NARROW[to, IO.STREAM] } ELSE { IF to=NIL THEN { name _ InName[wDir]; } ELSE IF ISTYPE[to, Rope.ROPE] THEN { name _ NARROW[to, Rope.ROPE]; IF Rope.IsEmpty[name] THEN name _ InName[wDir]; } ELSE { TerminalIO.WriteRope["WriteDesign does not support type of 'to' parameter\n"]; GOTO NotOpened; }; fileName _ CDIO.MakeName[name, "dale", wDir]; binFile _ FS.StreamOpen[fileName: fileName, accessOptions: $create, keep: 2 ! FS.Error => IF error.group#bug THEN { binFile_NIL; GOTO NotOpened } ]; iMadeTheOpen _ TRUE; }; IF NOT DoAttach[] THEN { IF ~quiet THEN WriteRope["not attached, locks are hold\n"]; IF ~quiet THEN Help[]; RETURN }; isQuiet _ quiet; designToWrite _ design; TokenIO.WriteInt[xChipndaleFile]; TokenIO.WriteInt[xVersion]; sealMark _ TokenIO.MarkAndWriteInt[0]; -- this is a bad seal TokenIO.WriteAtom[designToWrite.technology.key]; TokenIO.WriteRope[designToWrite.technology.name]; IF CDEvents.ProcessEvent[ev: writeEvent, design: designToWrite, x: NIL, listenToDont: TRUE].dont THEN { WriteRope["write not done\n"]; TokenIO.ReleaseWriter[]; IO.Close[binFile]; RETURN }; DoWriteDesign[]; TokenIO.UpdateMark[sealMark, -1]; -- validate seal TokenIO.ReleaseWriter[]; IF iMadeTheOpen THEN IO.Close[binFile]; WriteRope["\n"]; TerminalIO.WriteRope["design "]; TerminalIO.WriteRope[designToWrite.name]; TerminalIO.WriteRope[" written on file "]; IF iMadeTheOpen THEN TerminalIO.WriteRope[fileName]; TerminalIO.WriteLn[]; done _ TRUE; EXITS NotOpened => { IF ~quiet THEN TerminalIO.WriteRope["File not created\n"]; }; END; <<-- Module initialization>> writeEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$WriteTechnologyPrivate]; END.