<> <> <> <> DIRECTORY Ascii, Atom, CD, CDEnvironment, CDEvents, CDValue, Commander, CommandTool, FileNames, FS, Icons, IO, List, ProcessProps, Rope, RuntimeError, TerminalIO, TEditImpl USING [ReloadTable], --crazy tiptable load procedure TIPUser, UserProfile; CDEnvironmentImpl: CEDAR PROGRAM IMPORTS Atom, CD, CDEvents, CDValue, CommandTool, FileNames, FS, Icons, IO, List, ProcessProps, RuntimeError, Rope, TEditImpl, TerminalIO, TIPUser, UserProfile EXPORTS CDEnvironment = BEGIN <<-- tip tables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> <<>> SetTipTable: PUBLIC PROC [for: REF, tipTable: Rope.ROPE] = { tipTab: TIPUser.TIPTable _ NIL; IF Rope.IsEmpty[tipTable] THEN tipTable _ "Standard"; CDValue.Store[for, $TipTableName, tipTable]; IF Rope.Equal[tipTable, "Standard"] THEN tipTab _ InstallStandardTip[for] ELSE tipTab _ TryExplicitTipTable[for, tipTable]; IF tipTab#NIL THEN CDValue.Store[for, $TipTable, tipTab]; }; TryExplicitTipTable: PROC [for: REF, name: Rope.ROPE] RETURNS [tipTable: TIPUser.TIPTable] = { name _ MakeName[base: name, ext: "tip", wDir: TechWDir[for]]; tipTable _ TIPUser.InstantiateNewTIPTable[name ! FS.Error => { TerminalIO.WriteRopes["Tip-table not installed; ", error.explanation, "\n"]; GOTO oops }; TIPUser.InvalidTable => { TerminalIO.WriteRopes["Tip-table not installed; ", errorMsg, "\n"]; GOTO oops }; ]; EXITS oops => NULL }; InstallStandardTip: PROC [for: REF] RETURNS [tipTable: TIPUser.TIPTable _ NIL] = { WITH for SELECT FROM tech: CD.Technology => { profileKey: Rope.ROPE _ Rope.Cat["ChipNDale.", tech.name, ".TIP"]; techPart: Rope.ROPE _ MakeName[base: "ChipNDale", ext: "tip", modifier: tech.name, wDir: GetWorkingDirectory[tech]]; base: Rope.ROPE _ MakeName[base: "ChipNDale", ext: "tip", wDir: GetWorkingDirectory[NIL]]; default: Rope.ROPE _ Rope.Cat[techPart, " ", base]; tipTable _ TEditImpl.ReloadTable[oldTIP: NIL, profileKey: profileKey, default: default]; IF tipTable=NIL THEN { TerminalIO.WriteRopes["Tip-table for ", tech.name, " not installed\n"]; tipTable _ TryExplicitTipTable[for, "ChipNDale.tip"]; }; }; d: CD.Design => tipTable _ InstallStandardTip[d.technology]; ENDCASE => TerminalIO.WriteRope["Tip-table not installed\n"]; }; GetTipTable: PUBLIC PROC [for: REF] RETURNS [TIPUser.TIPTable] = { WITH CDValue.Fetch[boundTo: for, key: $TipTable, propagation: global] SELECT FROM tipTable: TIPUser.TIPTable => RETURN [tipTable]; ENDCASE => RETURN [NIL]; }; NoteProfileChange: UserProfile.ProfileChangedProc = { EachTech: CD.TechnologyEnumerator = { WITH CDValue.Fetch[tech, $TipTableName] SELECT FROM r: Rope.ROPE => IF Rope.Equal[r, "Standard"] THEN SetTipTable[tech, r]; ENDCASE => NULL; }; [] _ CD.EnumerateTechnologies[EachTech]; }; <<>> <<>> <<-- Icons ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> FetchIcon: PROC [for: REF, file: Rope.ROPE, n: NAT] RETURNS [icon: REF Icons.IconFlavor] = { if: Icons.IconFlavor; icon _ NEW[Icons.IconFlavor_tool]; file _ MakeName[base: file, ext: "icon", wDir: TechWDir[for]]; if _ Icons.NewIconFromFile[file, n ! RuntimeError.UNCAUGHT => GOTO Oops]; icon^ _ if; EXITS Oops => TerminalIO.WriteRope["**Icon not loaded\n"]; }; SetIcon: PUBLIC PROC [for: REF, file: Rope.ROPE, n: NAT] = { icon: REF Icons.IconFlavor _ FetchIcon[for, file, n]; CDValue.Store[for, $Icon, icon]; }; GetIcon: PUBLIC PROC [for: REF] RETURNS [Icons.IconFlavor] = { WITH CDValue.Fetch[for, $Icon, global] SELECT FROM ip: REF Icons.IconFlavor => RETURN [ip^]; ENDCASE => RETURN [Icons.IconFlavor[unInit]] }; SetPanelIcon: PUBLIC PROC [for: REF, file: Rope.ROPE, n: NAT] = { icon: REF Icons.IconFlavor _ FetchIcon[for, file, n]; CDValue.Store[for, $PanelIcon, icon]; }; GetPanelIcon: PUBLIC PROC [for: REF] RETURNS [Icons.IconFlavor] = { WITH CDValue.Fetch[for, $PanelIcon, global] SELECT FROM ip: REF Icons.IconFlavor => RETURN [ip^]; ENDCASE => RETURN [Icons.IconFlavor[unInit]] }; <<-- Working Directories ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> <<>> CheckWorkingDirectory: PROC [wDir: Rope.ROPE] RETURNS [slashWDir: Rope.ROPE] = { <<--if wDir is a directory, assign it to slashWDir>> <<--else slashWDir _ nil>> length: INT; IF FileNames.IsADirectory[wDir] AND NOT FileNames.IsAPattern[wDir] THEN { slashWDir _ FileNames.ConvertToSlashFormat[wDir]; length _ Rope.Length[slashWDir]; IF slashWDir=wDir AND length>0 AND slashWDir.Fetch[length-1]='/ THEN { RETURN [slashWDir]; } }; RETURN [NIL] }; SetWorkingDirectory: PUBLIC PROC [for: REF, wDir: Rope.ROPE] = { IF wDir=NIL THEN { WITH for SELECT FROM d: CD.Design => NULL; t: CD.Technology => { techName: Rope.ROPE _ t.name; IF techName=NIL THEN techName _ Atom.GetPName[t.key]; wDir _ UserProfile.Token[Rope.Cat["ChipNDale.", techName, ".BaseDirectory"]]; }; ENDCASE => IF for=NIL THEN { wDir _ UserProfile.Token["ChipNDale.BaseDirectory"]; }; IF wDir=NIL THEN wDir _ FileNames.CurrentWorkingDirectory[]; }; CDValue.Store[for, $WorkingDirectory, CheckWorkingDirectory[wDir]]; }; GetWorkingDirectory: PUBLIC PROC [for: REF] RETURNS [wDir: Rope.ROPE_NIL] = { WITH CDValue.Fetch[for, $WorkingDirectory, global] SELECT FROM r: Rope.ROPE => wDir _ CheckWorkingDirectory[r]; ENDCASE => NULL; }; <<>> DoWithWDir: PUBLIC PROC [wDir: Rope.ROPE, proc: PROC] = { ProcessProps.AddPropList[ propList: Atom.PutPropOnList[NIL, $WorkingDirectory, wDir], inner: proc ]; }; <<>> <<-- Names ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> MakeName: PUBLIC PROC [base: Rope.ROPE, ext: Rope.ROPE_NIL, wDir: Rope.ROPE_NIL, modifier: Rope.ROPE_NIL] RETURNS [Rope.ROPE] = { 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]; }; bang: INT = TrailingChar[base, '!]; <<--remove version number>> r: Rope.ROPE _ Rope.Substr[base: base, len: bang]; <<--include modifier>> IF ~modifier.IsEmpty[] THEN r _ Rope.Concat[r, modifier]; <<--include extension>> IF ~ext.IsEmpty[] AND (TrailingChar[r, '.]>=Rope.Length[r]) THEN { dot2: INT _ TrailingChar[ext, '.]; IF dot2>=Rope.Length[ext] THEN r _ Rope.Cat[r, ".", ext] ELSE r _ Rope.Concat[r, ext.Substr[dot2]] }; <<--include working directory>> IF wDir#NIL THEN { IF Rope.IsEmpty[r] OR (Rope.Fetch[r]#'/ AND Rope.Fetch[r]#'[) THEN r _ Rope.Concat[FileNames.Directory[wDir], r] }; <<--put version number back>> IF bang> <<-- Loader ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> SplitLine: PUBLIC PROC [line: Rope.ROPE] RETURNS [key, rest: Rope.ROPE_NIL] = { <<--splits a line into a keyword and the rest >> <<--returns>> <<-- key: keyword at beginning of line; >> <<-- (leading spaces and trailing separator [space or colon] removed)>> <<-- rest: rest of line (after separator)>> <<-- (leading spaces removed)>> leng: INT _ Rope.Length[line]; nextPos: INT _ 0; startPos: INT _ 0; <<--skip leading spaces>> WHILE startPos startPos _ startPos+1; ENDCASE => EXIT; ENDLOOP; <<--find position of separator>> nextPos _ startPos; WHILE nextPos EXIT; ENDCASE => nextPos _ nextPos+1; ENDLOOP; IF startPos> WHILE nextPos nextPos _ nextPos+1; ENDCASE => {rest _ Rope.Substr[line, nextPos, leng-nextPos]; RETURN} ENDLOOP; }; FetchKeyLine: PUBLIC PROC [fileName: Rope.ROPE, key: Rope.ROPE] RETURNS [entry: Rope.ROPE_NIL] = { <<--Searches for a line starting with key in file>> <<--Returns the rest of the line found or NIL if not found>> line, first, rest: Rope.ROPE; file: IO.STREAM; file _ FS.StreamOpen[fileName ! FS.Error => GOTO finish]; DO line _ IO.GetLineRope[file ! IO.EndOfStream => GOTO finish]; IF ~Rope.IsEmpty[line] THEN { [first, rest] _ SplitLine[line]; IF Rope.Equal[first, key] THEN RETURN [rest] } ENDLOOP; EXITS finish => NULL; }; StuffToCommandTool: PUBLIC PROC [r: Rope.ROPE, wDir: Rope.ROPE_NIL, searchPath: LIST OF Rope.ROPE_NIL] RETURNS [result: REF_NIL] = { RopeListPath: PROC [rl: LIST OF Rope.ROPE] RETURNS [path: List.LORA _ NIL] = { last: Rope.ROPE_NIL; FOR l: LIST OF Rope.ROPE _ rl, l.rest WHILE l#NIL DO IF ~Rope.IsEmpty[l.first] AND ~Rope.Equal[last, l.first, FALSE] THEN { last _ l.first; path _ CONS[last, path]; } ENDLOOP; RETURN [List.DReverse[path]] }; out: Rope.ROPE; --for the result rope returned by the CommandTool cmd: Commander.Handle _ NEW[Commander.CommandObject _ [ out: TerminalIO.TOS[], err: TerminalIO.TOS[], in: IO.noInputStream, propertyList: List.PutAssoc[key: $SearchRules, val: RopeListPath[searchPath], aList: NIL] ]]; Exec: PROC [] = { [out, result] _ CommandTool.DoCommandRope[commandLine: r, parent: cmd]; }; IF Rope.IsEmpty[r] THEN TerminalIO.WriteRopes["executes empty command\n"] ELSE { TerminalIO.WriteRopes["executes: """, r, """\n"]; DoWithWDir[wDir, Exec]; TerminalIO.WriteRopes["\n{", out, "}\n"]; }; }; <<>> ExecFileEntry: PUBLIC PROC [key: Rope.ROPE, technology: CD.Technology_NIL, modifier: Rope.ROPE_NIL] = { <<--checks whether a particular key is mentioned in a .CDLoadList file>> <<--if particular key is found, executes the rest of the line with a command tool>> <<--technology and modifier are used to make the name of the used .CDLoadList file>> <<--(using modifier .CDLoadList files for particular feature classes can be distinguished)>> <<--building of name for the .CDLoadList files:>> <<-- ChipNDale-CD.CDLoadList if {technology=NIL, modifier=NIL}>> <<-- ChipNDale-CD-modifier.CDLoadList if {technology=NIL, modifier#NIL}>> <<-- ChipNDale-technologyName.CDLoadList if {technology#NIL, modifier=NIL}>> <<-- ChipNDale-technologyName-modifier.CDLoadList if {technology#NIL, modifier#NIL}>> wDir: Rope.ROPE; --for working directories entry: Rope.ROPE; --for the line which will be stuffed into a command tool Fetch: PROC [mod: Rope.ROPE] = { <<--internal procedure>> <<--makes up the full path name of the .CDLoadList file>> <<--and looks for a particular entry line in it>> <<--mod: name for the technology>> IF modifier#NIL THEN mod _ Rope.Cat[mod, "-", modifier]; mod _ MakeName["ChipNDale-", "CDLoadList", wDir, mod]; entry _ FetchKeyLine[mod, key]; }; searchPath: LIST OF Rope.ROPE _ LIST[GetWorkingDirectory[NIL], "///Commands/"]; IF technology#NIL THEN { wDir _ GetWorkingDirectory[technology]; searchPath _ CONS[wDir, searchPath]; Fetch[technology.name]; }; IF entry=NIL THEN { wDir _ GetWorkingDirectory[NIL]; Fetch["CD"]; }; IF entry=NIL THEN TerminalIO.WriteRopes["command line for ", key, " not found\n"] ELSE [] _ StuffToCommandTool[entry, wDir, searchPath]; }; <<>> LoadTechnology: PUBLIC PROC [key: ATOM, name: Rope.ROPE] RETURNS [tech: CD.Technology_NIL] = { <<--makes all the necessary messages if not loaded>> IF key#NIL THEN tech _ CD.FetchTechnology[key]; IF tech=NIL THEN { autoLoadDefault: BOOL _ UserProfile.Boolean["ChipNDale.AutoLoad.Default", TRUE]; IF name=NIL THEN name _ Atom.GetPName[key]; IF UserProfile.Boolean[Rope.Concat["ChipNDale.AutoLoad.", name], autoLoadDefault] THEN { TerminalIO.WriteRopes["load technology """, name, """ \n"]; ExecFileEntry[name]; tech _ CD.FetchTechnology[key]; }; IF tech=NIL THEN TerminalIO.WriteRopes["technology '", name, "' not loaded\n"]; }; }; <<>> <<-- internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> TechWDir: PROC [for: REF] RETURNS [Rope.ROPE] = { WITH for SELECT FROM d: CD.Design => for _ d.technology ENDCASE => NULL; RETURN [GetWorkingDirectory[for]] }; TechnologyHasBeenRegisterd: CDEvents.EventProc = { WITH x SELECT FROM t: CD.Technology => { SetWorkingDirectory[t, NIL]; <> }; ENDCASE => NULL }; NewDesignHasBeenCreated: CDEvents.EventProc = { IF design#NIL THEN SetWorkingDirectory[design, FileNames.CurrentWorkingDirectory[]]; }; CDValue.RegisterKey[$TipTable, NIL, $CD]; CDValue.RegisterKey[$TipTableName, NIL, $CD]; CDValue.RegisterKey[$Icon, NIL, $CD]; CDValue.RegisterKey[$WorkingDirectory, NIL, $CD]; SetIcon[NIL, "ChipNDale.icons", 0]; SetPanelIcon[NIL, "ChipNDale.icons", 1]; SetWorkingDirectory[NIL, NIL]; UserProfile.CallWhenProfileChanges[NoteProfileChange]; CDEvents.RegisterEventProc[$CreateNewDesign, NewDesignHasBeenCreated]; CDEvents.RegisterEventProc[$RegisterTechnology, TechnologyHasBeenRegisterd]; END.