<> <> <> <> DIRECTORY Ascii, Atom, CD, CDEnvironment, CDEvents, CDOps, CDValue, Commander, CommandTool, FileNames, FS, Icons, IO, List, PopUpSelection, ProcessProps, Rope, RuntimeError, SystemNames, TerminalIO, TEditImpl USING [ReloadTable], --crazy, wonderful tiptable load procedure TIPUser, UserProfile; CDEnvironmentImpl: CEDAR PROGRAM IMPORTS Atom, CD, CDEvents, CDOps, CDValue, Commander, CommandTool, FileNames, FS, Icons, IO, List, PopUpSelection, ProcessProps, RuntimeError, Rope, SystemNames, TEditImpl, TerminalIO, TIPUser, UserProfile EXPORTS CDEnvironment = BEGIN <<-- versions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> <<>> cdVersion: PUBLIC NAT _ 25; preRelease: PUBLIC BOOL _ FALSE; date: Rope.ROPE = "April 17, 1987"; profilePrefix: PUBLIC Rope.ROPE _ IO.PutFR["ChipNDale%g.", [integer[cdVersion]]]; commandsPrefix: Rope.ROPE _ FileNames.ConvertToSlashFormat[SystemNames.LocalDir["Commands"]]; systemPrefix: Rope.ROPE _ FileNames.ConvertToSlashFormat[SystemNames.LocalDir["System"]]; Prefixed: PROC [r1, r2: Rope.ROPE_NIL] RETURNS [Rope.ROPE] = { RETURN [Rope.Cat[profilePrefix, r1, r2]] }; <<>> copyRight: Rope.ROPE = "Copyright (C) 1984, 1987 by Xerox Corporation. All rights reserved.\n\n"; <<>> <<-- tip tables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> <<>> SetTipTable: PUBLIC PROC [for: REF, tipTable: Rope.ROPE] = { 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.PutRopes["Tip-table not installed; ", error.explanation, "\n"]; GOTO oops }; TIPUser.InvalidTable => { TerminalIO.PutRopes["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 => { 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: Prefixed[tech.name, ".TIP"], default: default]; IF tipTable=NIL THEN { TerminalIO.PutRopes["* tip-table for ", tech.name, " not installed\n"]; tipTable _ TryExplicitTipTable[for, "ChipNDale.tip"]; }; }; d: CD.Design => tipTable _ InstallStandardTip[d.technology]; ENDCASE => TerminalIO.PutRope["* tip-table not installed\n"]; }; 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]; }; 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]; }; ReInstallStandardTipTables: Commander.CommandProc = { 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]; [] _ CDEvents.ProcessEvent[reInstallTipTables, NIL]; }; <<>> <<>> <<-- Icons ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> FetchIconFromFile: 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.PutRope["** icon not loaded\n"]; }; SetIcon: PUBLIC PROC [for: REF, file: Rope.ROPE, n: NAT] = { icon: REF Icons.IconFlavor _ FetchIconFromFile[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 _ FetchIconFromFile[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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> <<>> CheckWDir: PROC [wDir: Rope.ROPE] RETURNS [slashWDir: Rope.ROPE] = { <<--if wDir is a directory, return it in slash format>> <<--else return NIL>> length: INT; IF FileNames.IsADirectory[wDir] AND ~FileNames.IsAPattern[wDir] THEN { slashWDir _ FileNames.ConvertToSlashFormat[wDir]; length _ Rope.Length[slashWDir]; IF 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 t: CD.Technology => { techName: Rope.ROPE _ t.name; IF techName=NIL THEN techName _ Atom.GetPName[t.key]; wDir _ UserProfile.Token[Prefixed[techName, ".BaseDirectory"]]; }; d: CD.Design => NULL; ENDCASE => IF for=NIL THEN { wDir _ UserProfile.Token[Prefixed["BaseDirectory"]]; }; IF wDir=NIL THEN wDir _ FileNames.CurrentWorkingDirectory[]; }; CDValue.Store[for, $WorkingDirectory, CheckWDir[wDir]]; }; GetWorkingDirectory: PUBLIC PROC [for: REF] RETURNS [wDir: Rope.ROPE_NIL] = { WITH CDValue.Fetch[for, $WorkingDirectory, global] SELECT FROM r: Rope.ROPE => wDir _ CheckWDir[r]; ENDCASE => NULL; }; <<>> DoWithWDir: PUBLIC PROC [wDir: Rope.ROPE, proc: PROC] = { ProcessProps.AddPropList[ propList: Atom.PutPropOnList[NIL, $WorkingDirectory, wDir], inner: proc ]; }; <<>> <<-- Commander ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> RegisterCommander: PUBLIC PROC [key: Rope.ROPE, proc: Commander.CommandProc _ NIL, doc: Rope.ROPE _ NIL, clientData: REF _ NIL, interpreted: BOOL _ TRUE, technology: CD.Technology _ NIL] = { gWDir: Rope.ROPE _ GetWorkingDirectory[NIL]; Commander.Register[key: key, proc: proc, doc: doc, clientData: clientData, interpreted: interpreted]; Commander.Register[key: Rope.Cat[gWDir, key], proc: proc, doc: doc, clientData: clientData, interpreted: interpreted]; IF technology#NIL THEN { tWDir: Rope.ROPE _ GetWorkingDirectory[technology]; IF ~Rope.Equal[gWDir, tWDir] THEN Commander.Register[key: Rope.Cat[tWDir, key], proc: proc, doc: doc, clientData: clientData, interpreted: interpreted] } }; <<>> <<-- 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 { dir: Rope.ROPE _ FileNames.Directory[wDir]; IF ~Rope.IsEmpty[dir] THEN r _ Rope.Cat[FileNames.ConvertToSlashFormat[dir], r] } }; <<--put version number back>> IF bang> FindFile: PUBLIC PROC [base: Rope.ROPE, ext: Rope.ROPE_NIL, for: REF_NIL] RETURNS [fn: Rope.ROPE] = { searchPath: LIST OF Rope.ROPE _ LIST[commandsPrefix, systemPrefix]; AddToWDir: PROC [r: Rope.ROPE] = { IF ~Rope.IsEmpty[r] AND ~Rope.Equal[searchPath.first, r] THEN searchPath _ CONS[r, searchPath]; }; AddToWDir[GetWorkingDirectory[NIL]]; WITH for SELECT FROM rl: LIST OF Rope.ROPE => searchPath _ rl; r: Rope.ROPE => searchPath _ LIST[r]; r: REF TEXT => searchPath _ LIST[Rope.FromRefText[r]]; d: CD.Design => { AddToWDir[GetWorkingDirectory[d.technology]]; AddToWDir[GetWorkingDirectory[d]]; }; t: CD.Technology => { AddToWDir[GetWorkingDirectory[t]]; }; ENDCASE => NULL; AddToWDir[FileNames.CurrentWorkingDirectory[]]; IF Rope.Length[ext]>0 AND Rope.Fetch[ext, 0]#'. THEN ext _ Rope.Concat[".", ext]; fn _ FileNames.FileWithSearchRules[root: base, defaultExtension: ext, requireExtension: FALSE, requireExact: TRUE, searchRules: searchPath].fullPath; }; <<>> <<-- Loader ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>> RemoveSpaces: PUBLIC PROC [line: Rope.ROPE] RETURNS [Rope.ROPE_NIL] = { leng: INT _ Rope.Length[line]; start: INT _ 0; WHILE start start _ start+1; ENDCASE => EXIT; ENDLOOP; WHILE leng>start DO SELECT Rope.Fetch[line, leng-1] FROM Ascii.SP, Ascii.TAB => leng _ leng-1; ENDCASE => EXIT; ENDLOOP; IF leng>start THEN RETURN [Rope.Substr[line, start, leng-start]]; }; SplitLine: PUBLIC PROC [line: Rope.ROPE] RETURNS [key, rest: Rope.ROPE_NIL] = { 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, catchErrors: BOOL_TRUE, continueErrors: BOOL_TRUE] 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]] }; propertyList: List.AList _ List.PutAssoc[key: $StopOnFailure, val: $TRUE, aList: NIL]; --temporary 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: propertyList] ]]; Exec: PROC [] = { [out, result] _ CommandTool.DoCommandRope[commandLine: r, parent: cmd]; }; IF Rope.IsEmpty[r] THEN TerminalIO.PutRopes["executes empty command\n"] ELSE { TerminalIO.PutRopes["executes: """, r, """\n"]; DoWithWDir[wDir, Exec ! ABORTED => {TerminalIO.PutRope["\n**aborted\n"]; IF continueErrors THEN CONTINUE}; RuntimeError.UNCAUGHT => { IF ~catchErrors THEN REJECT ELSE SELECT PopUpSelection.Request[ header: "ERROR", choice: LIST["continue with ChipNDale", "debug"], headerDoc: "error while executing stuff", choiceDoc: LIST["usually ok", "land in debugger (abort will continue ChipNDale)"], timeOut: 600 --10 minutes ] FROM 1 => CONTINUE; -1 => {TerminalIO.PutRope["\n**Timed out request for debugging: reject will probably open a debugger window\n"]; REJECT}; 2 => REJECT; ENDCASE => CONTINUE; }; ]; TerminalIO.PutRopes["\n{", out, "}\n"]; }; }; <<>> ExecFileEntry: PUBLIC PROC [key: Rope.ROPE, technology: CD.Technology_NIL, modifier: Rope.ROPE_NIL, catchErrors: BOOL_TRUE, continueErrors: BOOL_TRUE] = { <<--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], commandsPrefix, systemPrefix]; 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.PutRopes["command line for ", key, " not found\n"] ELSE [] _ StuffToCommandTool[entry, wDir, searchPath, catchErrors, continueErrors]; }; <<>> 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 tech _ GetTechnology[key]; }; IF tech=NIL THEN { IF name#NIL THEN tech _ GetTechnology[name]; IF tech=NIL THEN { autoLoadDefault: BOOL _ UserProfile.Boolean[Prefixed["AutoLoad.Default"], TRUE]; IF Rope.IsEmpty[name] THEN name _ Atom.GetPName[key]; IF UserProfile.Boolean[Prefixed["AutoLoad.", name], autoLoadDefault] THEN { TerminalIO.PutRopes["load technology """, name, """ \n"]; ExecFileEntry[name, NIL, NIL, TRUE, TRUE]; IF key#NIL THEN tech _ GetTechnology[key]; IF tech=NIL THEN tech _ GetTechnology[name]; }; IF tech=NIL THEN TerminalIO.PutRopes["technology '", name, "' not loaded\n"]; }; }; }; <<>> AskAndExecute: Commander.CommandProc = { question: Rope.ROPE; cl: Rope.ROPE _ cmd.commandLine; IF Rope.IsEmpty[cl] THEN RETURN; question _ Rope.Cat["execute: ", Rope.Substr[base: cl, len: Rope.Length[cl]-1]]; IF ~TerminalIO.Confirm[text: question, dontLog: TRUE] THEN RETURN [$Failure, "denied"]; result _ CommandTool.DoCommand[commandLine: cl, parent: cmd]; }; <<>> GetTechnology: PUBLIC PROC [hint: REF] RETURNS [technology: CD.Technology] = { GetWithRope: PROC [name: Rope.ROPE] RETURNS [t: CD.Technology_NIL] = { EachTechnology: CD.TechnologyEnumerator = { IF Rope.Equal[tech.name, name, FALSE] OR Rope.Equal[Atom.GetPName[tech.key], name, FALSE] THEN {quit _ TRUE; technology _ tech} }; IF Rope.IsEmpty[name] THEN RETURN; [] _ CD.EnumerateTechnologies[EachTechnology]; }; WITH hint SELECT FROM tech: CD.Technology => RETURN [tech]; d: CD.Design => RETURN [d.technology]; a: ATOM => technology _ CD.FetchTechnology[a]; ENDCASE => NULL; IF technology=NIL THEN RETURN [GetWithRope[CDOps.ToRope[hint]]] }; <<>> <<-- 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[]]; }; reInstallTipTables: CDEvents.EventRegistration _ CDEvents.RegisterEventType[ $CDReRegisterTipTables]; 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]; CDEvents.RegisterEventProc[$CreateNewDesign, NewDesignHasBeenCreated]; CDEvents.RegisterEventProc[$RegisterTechnology, TechnologyHasBeenRegisterd]; RegisterCommander["CDReInstallTipTables", ReInstallStandardTipTables, "Reload TIP tables for standard ChipNDale technologies"]; RegisterCommander["AskFirst", AskAndExecute, "Conditionally executes command"]; TerminalIO.PutF["ChipNDale\n %g Version %g.%g for Cedar %g\n %g\n Copyright (C) 1984, 1987 by Xerox Corporation. All rights reserved.\n\n", [rope[IF preRelease THEN "PRE RELEASED" ELSE ""]], [integer[cdVersion/10]], [integer[cdVersion MOD 10]], [rope[SystemNames.ReleaseName[]]], [rope[date]] ]; END.