DIRECTORY AMEvents USING [CallDebugger], Atom USING [MakeAtom, GetProp, PutProp], CIFS USING [Error, Open, GetFC, read], ConvertUnsafe USING [AppendRope, ToRope], Directory USING [Lookup, GetProps, Error], File USING [Capability, nullCapability], FileIO USING [Open, OpenFailed], IO USING [CR, EndOf, EndOfStream, SyntaxError, Close, Flush, GetBlock, GetIndex, GetLength, int, GetCedarToken, PutChar, PutF, PutRope, ROPE, rope, RIS, SetIndex, SP, STREAM, TAB, GetToken, WhiteSpace, SkipOver, UserAborted], IOExtras USING [GetCedarScannerToken, FromTokenProc], Loader USING [Instantiate, Start, Error], PrincOps USING [ControlModule], Process USING [GetCurrent], Rope USING [Cat, Concat, Equal, Fetch, Find, IsEmpty, Length, Replace, Substr, Text], RopeInline USING [NewText], RTProcess USING [GetTotalPageFaults, StartWatchingFaults], SafeStorage USING [NWordsAllocated], ShowTime USING [GetMark, Microseconds, Show], System USING [GreenwichMeanTime], Time USING [Current], TiogaOps USING [AddLooks, CreateSimplePattern, FirstChild, GetRope, GoToPreviousCharacter, InsertChar, IsComment, Location, Next, NodeSearch, Paste, Pattern, Ref, SaveSpanForPaste, ViewerDoc, SelectPoint, LastLocWithin], TiogaExtraOps USING [GetFile], UserExec USING [HistoryEvent, ExecHandle, CheckForAbort, UserAbort, UserAborted, GetTheFile, GetStreams, ErrorThisEvent, GetDefaultExecHandle], UserExecExtras USING [CreateEvent, NewErrorThisEvent], UserExecPrivate USING [AcquireExec, EventFailed, ReleaseExec, Prompt, UpdateFrameCache, ExecPrivateRecord, StripComments, CreateSubEvent, methodList, MethodList, GetPrivateStuff, BlinkIcon, HistoryEventPrivateRecord], UserProfile USING [Boolean, CallWhenProfileChanges, ProfileChangedProc], ViewerClasses USING [Viewer], ViewerOps USING [FindViewer] ; UserExecMiscImpl: CEDAR PROGRAM IMPORTS AMEvents, Atom, CIFS, ConvertUnsafe, Directory, FileIO, IO, IOExtras, Loader, Rope, RopeInline, RTProcess, SafeStorage, ShowTime, Time, UserExec, Process, TiogaOps, TiogaExtraOps, UserExecExtras, UserExecPrivate, UserProfile, ViewerOps EXPORTS UserExec, UserExecExtras, UserExecPrivate = BEGIN OPEN IO; ExecHandle: TYPE = UserExec.ExecHandle; HistoryEvent: TYPE = UserExec.HistoryEvent ; ExecPrivateRecord: PUBLIC TYPE = UserExecPrivate.ExecPrivateRecord; HistoryEventPrivateRecord: PUBLIC TYPE = UserExecPrivate.HistoryEventPrivateRecord; DoIt: PUBLIC PROC [input: ROPE, exec: ExecHandle _ UserExec.GetDefaultExecHandle[], partOf: HistoryEvent _ NIL] = { private: REF UserExecPrivate.ExecPrivateRecord; execOwner: UNSAFE PROCESS; event, subEvent: HistoryEvent; privateEvent, privateSubEvent: REF UserExecPrivate.HistoryEventPrivateRecord; abortIfSubEventFails: BOOLEAN; start, current: INT _ 0; length: INT; mark: ShowTime.Microseconds _ 0; t0: System.GreenwichMeanTime; nWords: LONG CARDINAL _ 0; nFaults: INT _ 0; Release: PROC = TRUSTED { -- Process IF exec # NIL AND private.execState # destroyed AND UserExecPrivate.ReleaseExec[exec] THEN { IF private.process = Process.GetCurrent[] THEN ERROR; private.eventState _ readyForNext; IF private.execState = listening THEN UserExecPrivate.Prompt[private.eventNum, exec]; }; }; {ENABLE UNWIND => Release[]; ShowStats: PROC = { IF showStats AND exec # NIL AND NOT private.dontPrompt THEN { out: STREAM = UserExec.GetStreams[exec].out; nw: INT _ SafeStorage.NWordsAllocated[] - nWords; t: System.GreenwichMeanTime; seconds: LONG CARDINAL; nf: INT; Put: PROC [char: CHAR] RETURNS[BOOL _ FALSE] = {out.PutChar[char]}; out.PutF["*n {"]; TRUSTED {t _ Time.Current[]}; seconds _ t - t0; IF seconds > 60 THEN { out.PutF["%d minutes, %d seconds", int[seconds/60], int[seconds MOD 60]]; } ELSE { ShowTime.Show[from: mark, p: Put, places: 2]; out.PutRope[" seconds"]; }; IF nw > 0 AND nw < 10000000 THEN out.PutF[", %d words", int[nw]]; TRUSTED {nf _ RTProcess.GetTotalPageFaults[] - nFaults}; IF nf > 0 AND nf < 10000000 THEN out.PutF[", %d page faults", int[nf]]; out.PutChar['}]; }; }; IF exec # NIL THEN { private _ UserExecPrivate.GetPrivateStuff[exec]; execOwner _ private.execOwner; IF UserExecPrivate.AcquireExec[exec] THEN TRUSTED { -- Process IF private.process = Process.GetCurrent[] THEN ERROR; -- since Read Eval Print acquires exec first, this must be an event coming in from somewhere else. IF private.execState = notListening OR private.execState = dormant THEN { IF partOf # NIL THEN privateEvent _ partOf.privateStuff; UserExecPrivate.Prompt[ IF partOf # NIL THEN privateEvent.eventNum ELSE private.eventNum, -- if partof was specified, then use its eventNumber. exec]; } ELSE IF private.eventState = readyForNext THEN private.eventState _ running ELSE ERROR; UserExec.GetStreams[exec].out.PutRope[input]; }; }; event _ IF partOf # NIL THEN partOf ELSE UserExecExtras.CreateEvent[exec, input]; subEvent _ event; privateEvent _ event.privateStuff; privateSubEvent _ subEvent.privateStuff; length _ Rope.Length[input]; DO stream: STREAM; substr: ROPE _ NIL; whiteSpace: BOOLEAN _ TRUE; UserExec.CheckForAbort[exec]; IF current = length THEN EXIT; start _ current; WHILE current < length DO char: CHARACTER _ Rope.Fetch[input, current]; TerminatesAtCurrent: PROC RETURNS[BOOL] = { count: INT _ start; fromTokenProc: IOExtras.FromTokenProc = { count _ count + token.next; IF token.kind = tokenCOMMENT AND closure.proc[closure.data, token.next - 1] = '\n THEN count _ count - 1; -- cr is (incorrectly) included in comment. without this check, test would say that CR is not a legitimate terminator in this case }; stream _ RIS[input, stream]; IO.SetIndex[stream, start]; IF NOT Rope.Equal[IO.GetCedarToken[stream! IO.EndOfStream => GOTO Yes], "_"] THEN RETURN[TRUE]; IO.SetIndex[stream, start]; DO IOExtras.GetCedarScannerToken[stream, fromTokenProc ! IO.SyntaxError => CONTINUE ]; IF count = current - 1 THEN GOTO Yes -- stopped just before the desired place. ELSE IF count >= current THEN GOTO No; ENDLOOP; EXITS No => RETURN[FALSE]; Yes => RETURN[TRUE]; }; current _ current + 1; SELECT char FROM SP => IF whiteSpace THEN start _ current; -- necessary (aesthetic) for compound events '\\ => current _ current + 1; -- from the standpoint of terminating the input, ignore next character. CR, TAB => { IF whiteSpace THEN {start _ current; LOOP} ELSE IF start = 0 AND current = length THEN substr _ input -- typical case ELSE IF current = length OR TerminatesAtCurrent[] THEN substr _ Rope.Substr[base: input, start: start, len: current - start] ELSE LOOP; abortIfSubEventFails _ FALSE; EXIT; }; '; => { IF current = length OR TerminatesAtCurrent[] THEN { substr _ Rope.Concat[Rope.Substr[base: input, start: start, len: current - start - 1], "\n"]; -- convert ; to CR so commands can all assume they are given a single line terminated by a CR. abortIfSubEventFails _ TRUE; EXIT; }; }; ENDCASE => whiteSpace _ FALSE; REPEAT FINISHED => substr _ Rope.Substr[input, start, current]; -- e.g. terminate in ? ENDLOOP; -- of WHILE loop that breaks into segments. BEGIN ENABLE { IO.UserAborted => { privateEvent.state _ aborted; privateSubEvent.state _ aborted; ShowStats[]; }; -- let error go through UserExec.ErrorThisEvent => { IF NOT Rope.IsEmpty[msg] THEN UserExec.GetStreams[exec].out.PutF["*n*e%g*s", rope[msg]]; privateEvent.state _ causedAnError; privateSubEvent.state _ causedAnError; IF exec.viewer.iconic THEN UserExecPrivate.BlinkIcon[exec.viewer]; ShowStats[]; IF NOT abortIfSubEventFails THEN LOOP; -- and go on with next subevent. }; -- otherwise let error go through. UserExecExtras.NewErrorThisEvent => { IF NOT Rope.IsEmpty[msg] THEN UserExec.GetStreams[exec].out.PutF["*n*e%g*s", rope[msg]]; privateEvent.state _ causedAnError; privateSubEvent.state _ causedAnError; UserExecPrivate.EventFailed[event: event, offender: offender]; IF exec.viewer.iconic THEN UserExecPrivate.BlinkIcon[exec.viewer]; ShowStats[]; IF NOT abortIfSubEventFails THEN LOOP; -- and go on with next subevent. }; -- otherwise let error go through. UNWIND => { privateEvent.state _ causedAnError; privateSubEvent.state _ causedAnError; IF exec.viewer.iconic AND private.execState # dormant THEN UserExecPrivate.BlinkIcon[exec.viewer]; }; }; inRopeStream: STREAM = RIS[rope: substr]; line: ROPE; firstToken: ROPE; firstToken _ IO.GetToken[inRopeStream]; IF Rope.IsEmpty[firstToken] THEN {IF event # NIL AND event.subEvents = NIL AND current = length AND exec # NIL THEN private.continuation _ TRUE; LOOP; -- white space on line in compound event. }; IF event # NIL AND (event.subEvents # NIL OR current # length OR input # event.input) THEN { -- second case says this is a compound event. third says came from command file, where input field is @file and input (obtained from private.input) is the expansion subEvent _ UserExecPrivate.CreateSubEvent[event: event, input: substr]; privateSubEvent _ subEvent.privateStuff; UserExec.GetStreams[exec].out.PutF["*n"]; -- if previous event caused some output, want this to go on fresh line. See comments in userexecimpl regarding LogNewLine as to why just don't call NewLine directly. }; line _ UserExecPrivate.StripComments[event, substr]; IF line # substr THEN -- some comments {[] _ RIS[rope: line, oldStream: inRopeStream]; IO.SkipOver[inRopeStream, IO.WhiteSpace]; IF inRopeStream.EndOf[] THEN {privateSubEvent.state _ completed; LOOP}; -- nothing there but a comment. }; subEvent.commandLine _ line; subEvent.commandLineStream _ inRopeStream; mark _ ShowTime.GetMark[]; nWords _ SafeStorage.NWordsAllocated[]; TRUSTED {t0 _ Time.Current[]; nFaults _ RTProcess.GetTotalPageFaults[]}; IF privateSubEvent.showInput THEN UserExec.GetStreams[exec].out.PutF["*n>%g", rope[line]]; FOR lst: UserExecPrivate.MethodList _ UserExecPrivate.methodList, lst.rest UNTIL lst = NIL DO subEvent.commandLine _ line; [] _ RIS[rope: line, oldStream: subEvent.commandLineStream]; -- load commandLineStream. Have to do it each time because the method might read from the commandLine before it determines that it is not applicable. IF lst.first.proc[event: subEvent, exec: exec, clientData: lst.first.clientData] THEN EXIT; REPEAT FINISHED => ERROR UserExecExtras.NewErrorThisEvent[event: subEvent, msg: Rope.Concat[firstToken, " not a command.\n"], offender: firstToken]; ENDLOOP; -- methodlist loop END; -- of process substr. ShowStats[]; privateSubEvent.state _ completed; ENDLOOP; -- substr loop privateEvent.state _ completed; Release[]; }; }; -- DoIt EventFailed: PUBLIC PROC[event: HistoryEvent, msg: ROPE _ NIL, offender: ROPE _ NIL] = { privateEvent: REF UserExecPrivate.HistoryEventPrivateRecord = event.privateStuff; IF NOT Rope.IsEmpty[msg] THEN ERROR UserExecExtras.NewErrorThisEvent[event, msg, offender] ELSE privateEvent.offender _ offender; }; RopeFromCMFile: PUBLIC PROC [file: ROPE, event: HistoryEvent, exec: ExecHandle] RETURNS[contents: ROPE, name: ROPE] = {ENABLE FileIO.OpenFailed => { SELECT why FROM fileNotFound => { name _ UserExec.GetTheFile[file: file, defaultExt: "cm", event: event, exec: exec]; IF name # NIL THEN {contents _ RopeFromFile[name]; CONTINUE}; name _ UserExec.GetTheFile[file: file, defaultExt: "commands", event: event, exec: exec]; IF name # NIL THEN {contents _ RopeFromFile[name]; CONTINUE}; }; illegalFileName => NULL; ENDCASE => REJECT; ERROR UserExecExtras.NewErrorThisEvent[event: event, msg: Rope.Concat[fileName, " not found"], offender: fileName]; }; length: INT; IF Rope.Fetch[file, 0] = '@ THEN file _ Rope.Substr[file, 1]; -- strip off @ length _ Rope.Length[file]; IF length = 0 THEN RETURN; IF Rope.Fetch[file, length - 1] = '@ THEN file _ Rope.Substr[base: file, len: length - 1]; -- strip off trailing @ name _ file; contents _ NIL; contents _ RopeFromFile[fileName: file ! FileIO.OpenFailed => IF why = fileNotFound AND Rope.Find[file, "."] = -1 THEN {name _ Rope.Concat[file, ".cm"]; CONTINUE} ]; IF contents # NIL THEN RETURN; contents _ RopeFromFile[fileName: name ! FileIO.OpenFailed => IF why= fileNotFound THEN {name _ Rope.Concat[file, ".commands"]; CONTINUE} ]; IF contents # NIL THEN RETURN; contents _ RopeFromFile[fileName: name]; }; RopeFromFile: PROC [fileName: ROPE] RETURNS [value: ROPE] = TRUSTED { -- LOOPHOLE handle: IO.STREAM _ FileIO.Open[fileName: fileName, accessOptions: read, createOptions: oldOnly]; length: LONG INTEGER _ handle.GetLength[]; text: Rope.Text _ RopeInline.NewText[length]; [] _ handle.GetBlock[LOOPHOLE[text, REF TEXT]]; IO.Close[handle]; RETURN[text]; }; StripComments: PUBLIC PROC [event: UserExec.HistoryEvent, rope: ROPE] RETURNS [ROPE] = { pos1, pos2: INT _ 0; IF Rope.Find[s1: rope, s2: "//"] # -1 THEN UserExec.ErrorThisEvent[event, "// convention for comments no longer implemented. Use -- instead."]; pos1 _ 0; WHILE (pos1 _ Rope.Find[s1: rope, s2: "--", pos1: pos1]) # -1 DO pos3: INT _ Rope.Find[s1: rope, s2: "--", pos1: pos1 + 2]; pos2 _ Rope.Find[s1: rope, s2: "\n", pos1: pos1]; IF pos2 = -1 THEN pos2 _ Rope.Length[rope]; IF pos3 = -1 THEN pos3 _ Rope.Length[rope] ELSE pos3 _ pos3 + 2; rope _ Rope.Replace[base: rope, start: pos1, len: MIN[pos2, pos3] - pos1]; ENDLOOP; RETURN[rope]; }; CorrectionDisabled: PUBLIC PROC[event: HistoryEvent] RETURNS[disabled: BOOL] = { RETURN[IF event = NIL THEN FALSE ELSE event.dontCorrect]; }; PrintDeclFromSource: PUBLIC PROC [target: ROPE, file: ROPE, exec: UserExec.ExecHandle] RETURNS [value: BOOLEAN] = { out: IO.STREAM = UserExec.GetStreams[].out; fileAtom: ATOM = Atom.MakeAtom[file]; doc: TiogaOps.Ref; viewer: ViewerClasses.Viewer; pattern: TiogaOps.Pattern; start, end: TiogaOps.Location; found, inline: BOOL; r: ROPE; stream: IO.STREAM; inner: PROC [root: TiogaOps.Ref] = { TRUSTED {doc _ LOOPHOLE[Atom.GetProp[atom: fileAtom, prop: $Root]]}; IF doc # NIL THEN NULL ELSE IF (viewer _ ViewerOps.FindViewer[file]) # NIL THEN doc _ TiogaOps.ViewerDoc[viewer] ELSE Atom.PutProp[atom: fileAtom, prop: $Root, val: doc _ TiogaExtraOps.GetFile[file ! CIFS.Error => CONTINUE]]; IF doc = NIL THEN {value _ FALSE; RETURN}; pattern _ TiogaOps.CreateSimplePattern[target]; -- does CreateSimplePattern ignore comments? start _ [doc, 0]; DO PrintChildren: PROC [node: TiogaOps.Ref, onlyComments: BOOL _ FALSE] = { child: TiogaOps.Ref _ TiogaOps.FirstChild[node]; UserExec.CheckForAbort[exec]; DO IF child = NIL THEN RETURN ELSE IF (onlyComments OR NOT inline) AND NOT TiogaOps.IsComment[child] THEN RETURN ELSE { IF Rope.IsEmpty[TiogaOps.GetRope[child]] THEN onlyComments _ TRUE ELSE Show[child]; PrintChildren[child, onlyComments]; }; child _ TiogaOps.Next[child]; ENDLOOP; }; Show: PROC [node: TiogaOps.Ref, start: INT _ 0, end: INT _ -1] = { r: ROPE = TiogaOps.GetRope[node]; len: INT = Rope.Length[r]; UserExec.CheckForAbort[exec]; IF end = -1 THEN end _ len; TiogaOps.InsertChar['\n]; TiogaOps.GoToPreviousCharacter[]; -- If we are at the end of the typescript, Paste will act like a stuff, which is not what we want TiogaOps.SaveSpanForPaste[startLoc: [node, start], endLoc: [node, end]]; TiogaOps.Paste[]; IF TiogaOps.IsComment[node] THEN TiogaOps.AddLooks["c"]; TiogaOps.SelectPoint[viewer: exec.viewer, caret: TiogaOps.LastLocWithin[TiogaOps.ViewerDoc[exec.viewer]]]; -- go to end. assumes that only one node in typescript. }; i: INT; UserExec.CheckForAbort[exec]; [found, start, end] _ TiogaOps.NodeSearch[pattern: pattern, startLoc: start, endLoc: start]; IF NOT found THEN {value _ FALSE; RETURN}; r _ TiogaOps.GetRope[start.node]; IF TiogaOps.IsComment[start.node] THEN { -- work around until CreateSimplePattern can take comment argument, or CreateGeneralPattern can take rope argument start.where _ Rope.Length[r]; -- skip to end. StepForward no good as this would cause match not to succeed if the target was the first thing in the next node, e.g. IO.Put? LOOP; }; stream _ IO.RIS[r, stream]; IO.SetIndex[stream, end.where + 1]; i _ start.where; WHILE i > 0 DO i _ i - 1; SELECT Rope.Fetch[r, i] FROM '\n, '; => EXIT; ' => LOOP; ENDCASE => GOTO NotDecl; REPEAT NotDecl => {start _ end; LOOP}; ENDLOOP; DO token: ROPE = IO.GetCedarToken[stream ! IO.EndOfStream => GOTO NotDecl]; IF Rope.Equal[token, ":"] THEN {start.where _ IO.GetIndex[stream]; EXIT}; -- Yes IF Rope.Equal[token, ","] THEN {[] _ IO.GetCedarToken[stream ! IO.EndOfStream => GOTO NotDecl]; LOOP}; -- e.g. Foo, Fie: type = ... GOTO NotDecl; REPEAT NotDecl => {start _ end; LOOP}; ENDLOOP; out.Flush[]; IF start.node # TiogaOps.FirstChild[doc] THEN { -- node structure being used inline _ TiogaOps.NodeSearch[pattern: TiogaOps.CreateSimplePattern["INLINE"], startLoc: start, endLoc: TiogaOps.LastLocWithin[start.node]].found; Show[start.node, start.where]; PrintChildren[start.node]; } ELSE { end: INT = FindEnd[r, start.where]; inline _ TiogaOps.NodeSearch[pattern: TiogaOps.CreateSimplePattern["INLINE"], startLoc: start, endLoc: [start.node, end]].found; Show[start.node, start.where, end]; }; TiogaOps.SelectPoint[viewer: exec.viewer, caret: TiogaOps.LastLocWithin[root]]; -- go to end. assumes that only one node in typescript. value _ TRUE; RETURN; ENDLOOP; }; inner[TiogaOps.ViewerDoc[exec.viewer]]; }; -- of PrintDeclFromSource FindEnd: PROC [nodeRope: ROPE, start: INT] RETURNS[end: INT] = { i: INT; inComment: BOOL _ FALSE; blankLine: BOOL _ FALSE; thisChar, lastChar: CHARACTER; i _ Rope.Find[nodeRope, ";", start] + 1; IF i = -1 THEN RETURN[Rope.Length[nodeRope]]; DO lastChar _ thisChar; thisChar _ Rope.Fetch[nodeRope, i]; i _ i + 1; SELECT thisChar FROM '- => { blankLine _ FALSE; IF lastChar = '- THEN inComment _ NOT inComment; end _ i -1; }; '\n => { IF blankLine THEN RETURN; -- blank line, usually indicates end of commented area. Subsequent comments between here and end probably refer to what follows. blankLine _ TRUE; inComment _ FALSE; }; ' , '\t => NULL; ENDCASE => { blankLine _ FALSE; IF ~inComment THEN RETURN; end _ i -1; }; -- anything seen outside of a comment means terminate. ENDLOOP; }; FileNotFound: PUBLIC SIGNAL [name: ROPE, defaultExt: ROPE _ NIL] RETURNS [shouldBe: ROPE] = CODE; RunBCDFile: PUBLIC PROCEDURE[fileName: ROPE, fileCapability: File.Capability _ File.nullCapability, callDebuggerFirst: BOOL _ FALSE, out: STREAM] RETURNS[name: ROPE, error: ROPE] = { ENABLE FileNotFound => RESUME[SIGNAL FileNotFound[name: fileName, defaultExt: "bcd"]]; warnings: ROPE; IF fileCapability # File.nullCapability THEN name _ fileName ELSE IF Rope.Find[s1: fileName, s2: "."] = -1 THEN name _ Rope.Concat[fileName, ".bcd"] ELSE name _ fileName; [name, error, warnings] _ LoadAndGo[name, fileCapability, callDebuggerFirst]; IF error # NIL THEN error _ Rope.Cat[error, ": ", fileName] ELSE { IF warnings # NIL THEN out.PutF["*n*m%g*s\n", rope[warnings]]; out.PutF["*nLoaded and started: %g\n", rope[name]]; }; }; LoadAndGo: PROC [fileName: ROPE, fileCapability: File.Capability, callDebuggerFirst: BOOL _ FALSE] RETURNS [name, error, warnings: ROPE] = TRUSTED { -- ConvertUnsafe ls: LONG STRING = [100]; cm: PrincOps.ControlModule; unboundImports: BOOLEAN; IF fileCapability = File.nullCapability THEN { IF Rope.Find[fileName, ">"] # -1 OR Rope.Find[fileName, "/"] # -1 THEN { -- use cifs err: ROPE; fileCapability _ CIFS.GetFC[CIFS.Open[name: fileName, mode: CIFS.read ! CIFS.Error => TRUSTED { err _ error; CONTINUE; }; ]]; error _ err; } ELSE { ConvertUnsafe.AppendRope[to: ls, from: fileName]; fileCapability _ Directory.Lookup[ls ! Directory.Error => { SELECT type FROM invalidFileName => error _ "Illegal file name"; fileNotFound => { fileName _ NARROW[SIGNAL FileNotFound[NIL, NIL]]; -- going to be caught in RunBCDFile and the appropriate arguments to the signal filled in . IF fileName # NIL THEN { ls.length _ 0; ConvertUnsafe.AppendRope[to: ls, from: fileName]; RETRY; }; error _ "Couldn't find a runnable file named"; }; ENDCASE => error _ "Lookup failed on"; CONTINUE; } ]; }; }; IF error = NIL THEN [cm, unboundImports] _ Loader.Instantiate[file: fileCapability, offset: 1, codeLinks: TRUE ! Loader.Error => { error _ SELECT type FROM invalidBcd => "Invalid Bcd", fileNotFound => "File Not Found", versionMismatch => "Version MisMatch", loadStateFull => "Load State Full, Can't Load", insufficientVM => "Insufficient VM", ENDCASE => ERROR; IF message # NIL THEN error _ Rope.Cat[error, ": ", ConvertUnsafe.ToRope[LOOPHOLE[message, LONG STRING]]]; CONTINUE; } ]; IF error = NIL THEN { IF ls.length # 0 THEN [] _ Directory.GetProps[fileCapability, ls ! Directory.Error => CONTINUE]; name _ IF ls.length # 0 THEN ConvertUnsafe.ToRope[ls] -- GetProps writes the full name into the long string. ELSE fileName; }; IF error = NIL THEN { IF callDebuggerFirst THEN AMEvents.CallDebugger[Rope.Concat["Loaded ", name]]; Loader.Start[cm ! ABORTED => {error _ "Execution Aborted"; CONTINUE}]; }; UserExecPrivate.UpdateFrameCache[]; IF unboundImports THEN warnings _ "(there are unbound imports)"; }; showStats: PUBLIC BOOLEAN _ FALSE; SetShowStats: UserProfile.ProfileChangedProc = TRUSTED { -- RTProcess showStats _ UserProfile.Boolean["ShowStatistics", FALSE]; IF showStats THEN RTProcess.StartWatchingFaults[]; }; UserProfile.CallWhenProfileChanges[SetShowStats]; END. -- of UserExecMiscImpl August 20, 1982 1:37 pm fixed LoadAndGo to use Loader.Instantiate and Loader.Start instead of Runtime.RunConfig. öLast Edited by: teitelman, May 23, 1983 6:31 pm Types connecting concrete and opaque types to access currentEvent, dontPrompt, continuation in DoIt, currentEvent in CorrectionEnabled processing individual events break input up into segments delimited by cr or ; -- current is one beyond the character just read. We want to know if that character, e.g. CR could be the terminator. Therefore, we want to test and see if the scan stopped just before that character. '' => current _ current + 1; -- from the standpoint of terminating the input, ignore next character. Whether ' or ^ is interpreted as special for command line will have to wait until we decide if this is a command or an expression. '^ => SELECT Rope.Fetch[input, current - 2] FROM SP, '\n, '\t => current _ current + 1; -- compromise. ^{cr} could end a line consisting of a mesa expression. Therefore, only give ^ its special interpretation (a la Alto exec) when preceded by white space. ENDCASE; otherwise, keep going, e.g. CR is in middle of rope. current = length check says if this is the end of the rope, no point in calling ProperlyTerminated otherwise, keep going, e.g. ; is in middle of rope. process substr first try just filename no extension specified, try .cm no extension specified, try .commands Think about using RopeIO WHILE (pos1 _ Rope.Find[s1: rope, s2: "//", pos1: pos1]) # -1 DO pos2 _ Rope.Find[s1: rope, s2: "\n", pos1: pos1]; IF pos2 = -1 THEN pos2 _ Rope.Length[rope]; rope _ Rope.Replace[base: rope, start: pos1, len: pos2 - pos1 + 1]; ENDLOOP; looking up declarations in file idea is to avoid printing out a procedure which happens to be a child of this node but do want to print out inline definitions (non-comment children) and do want to print out comments that are separated by empty nodes. Thus as soon as you see an empty node, only consider comments subsequently. ELSE { out.PutRope[IF start = 0 AND end = len THEN r ELSE Rope.Substr[base: r, start: start, len: end - start]]; out.PutChar['\n]; }; TiogaOps.CallWithLocks[proc: inner, root: TiogaOps.ViewerDoc[exec.viewer]]; -- check when bill is here as to why this locks up running bcds printing statistics Edited on December 14, 1982 11:40 pm, by Teitelman changed catch phrase, eliminating ANY, moving corresponding stuff to UNWIND. problem with informational signals when planting breakpoints under DoIt changes to: DoIt Edited on ile userexecmiscimpl compile userexecmisDecember 22, 1982 12:00 pm, by Teitelman changes to: DIRECTORY, IMPORTS, DoIt Edited on January 21, 1983 4:10 pm, by Teitelman changes to: DoIt, Release (local of DoIt) Edited on January 23, 1983 5:08 pm, by Teitelman changes to: DoIt Edited on March 6, 1983 2:42 pm, by Teitelman changes to: DIRECTORY, DoIt, RopeFromCMFile Edited on March 10, 1983 3:07 am, by Teitelman changes to: DIRECTORY, EXPORTS, IMPORTS, DoIt, RopeFromCMFile Edited on March 13, 1983 2:27 pm, by Teitelman changes to: DoIt Edited on March 31, 1983 3:32 pm, by Teitelman changes to: DoIt Edited on April 7, 1983 2:42 pm, by Teitelman changes to: DIRECTORY, RunBCDFile, LoadAndGo, UserProfile, IMPORTS Edited on April 15, 1983 3:27 pm, by Teitelman changes to: DoIt Edited on April 20, 1983 10:00 am, by Teitelman changes to: DoIt, EventFailed, RopeFromCMFile, DIRECTORY, LoadAndGo, DIRECTORY, ShowStats (local of DoIt), DIRECTORY, IMPORTS, ShowStats (local of DoIt), DIRECTORY, ShowStats (local of DoIt) Edited on May 13, 1983 1:03 pm, by Teitelman changes to: LoadAndGo Edited on May 23, 1983 6:31 pm, by Teitelman changes to: ShowStats (local of DoIt) Ê1– "Cedar" style˜J™0šÏk ˜ Jšœ œ˜Jšœœ˜(Jšœœ˜&Jšœœ˜)Jšœ œ˜*Jšœœ˜(Jšœœ˜ Jšœœœ|œœ œœœ/˜áJšœ œ'˜5Jšœœ˜)Jšœ œ˜Jšœœ˜JšœœK˜UJšœ œ ˜Jšœ œ+˜:Jšœ œ˜$Jšœ œ˜-Jšœœ˜!Jšœœ ˜Jšœ œÎ˜ÜJšœœ ˜Jšœ œ˜Jšœœ"˜6JšœœÄ˜ÙJšœ œ7˜HJšœœ ˜Jšœ œ ˜J˜J˜—J˜JšÐblœœœ˜ J˜Jšœ9œ±˜óJ˜Jšœ,˜3J˜Jšœœœœ˜head™JšÏn œœ˜'JšŸ œœ˜,šœ$™$šŸœœœ%˜CJ™[—JšŸœœœ-˜S——šœ™š Ÿœœœ œMœ˜sJšœ œ#˜/Jšœ œœ˜Jšœ˜Jšœœ+˜MJšœœ˜Jšœœ˜Jšœœ˜ J˜!J˜Jšœœœ˜Jšœ œ˜šŸœœœÏc ˜%š œœœœÐbo œ˜\Jšœ(œœ˜5Jšœ#˜#Jšœœ0˜UJ˜—J˜—šœœœ˜J˜—šŸ œœ˜š œ œœœœ˜;šœ˜Jšœœ!˜,Jšœœ*˜1J˜Jšœ œ˜Jšœœ˜Jš Ÿœœœœœœ˜CJšœ˜Jšœ˜Jšœ˜šœœ˜Jšœ@œ˜IJ˜—šœ˜J˜.Jšœ˜Jšœ˜—Jšœœœ"˜BJšœ1˜8Jšœœœ)˜IJšœ˜J˜—J˜——J˜šœœ˜Jšœ0˜0Jšœ˜š œ¡ œœœ  ˜@Jšœ(œ c˜˜šœ"œœ˜JJšœ œœ$˜8šœ˜Jš œ œœœ 5˜xJšœ˜—J˜—Jšœœ#œ˜KJšœœ˜ Jšœ-˜-J˜—J˜—Jš œœ œœœ)˜QJ˜J˜"J˜(J˜Jš 1™1š˜Jšœœ˜Jšœœœ˜Jšœ œœ˜Jšœ˜Jšœœœ˜J˜šœ˜Jšœ œ˜-šŸœœœœ˜+Jšœœ ˜šŸ œ˜)Jšœ˜šœœ3˜SJšœ ‚˜›—J˜—Jšœ œ˜Jšœ˜Jšœœ œœœ œœœ˜_Jšœ˜š˜šœ5˜5Jšœœ˜Jšœ˜—JšœÈ™ÈJšœœœ )˜NJšœœœœ˜&Jšœ˜—š˜Jšœœœ˜Jšœœœ˜—J˜—J˜šœ˜Jšœœ œ ,˜VJšœ Ê™ç™šœ ™*Jšœ% ¨™ÏJšœ™——Jšœ G˜ešœ˜ Jšœ œœ˜*Jš œœ œœ ˜JJšœœœœF˜|Jšœœ˜ Jšœœ˜šœ˜J™——Jšœ˜—˜šœœ˜4Jšœ^ ^˜¼Jšœœ˜Jšœ˜Jšœ˜J™3—Jšœ˜—Jšœœ˜—Jš˜Jšœ1 ˜OJšœ +˜4——J˜Jš ™š˜š˜˜J˜Jšœ ˜ Jšœ ˜ Jšœ ˜—˜Jšœœœ;˜XJšœ$˜$Jšœ&˜&Jšœœ(˜BJšœ ˜ Jš œœœœ  ˜HJšœ "˜&—˜%Jšœœœ;˜XJšœ$˜$Jšœ&˜&J˜>Jšœœ(˜BJšœ ˜ Jš œœœœ  ˜HJšœ "˜&—šœ˜ Jšœ#˜#Jšœ&˜&Jšœœœ(˜bJšœ˜—J˜—Jšœœœ˜)Jšœœ˜ Jšœ œ˜J˜'šœ˜ Jšœœ œœœœœœœœ˜oJšœ *˜0J˜—šœ œœœœœœ ¦˜ƒJ˜GJšœ(˜(Jšœ+ ¥˜ÐJ˜—Jšœ4˜4šœœ ˜&Jšœœ&˜/J˜)Jšœœ%œ  ˜hJ˜—Jšœ˜Jšœ*˜*J˜Jšœ'˜'JšœA˜HJšœœ9˜ZšœHœœ˜]Jšœ˜Jšœœ5 •˜ÒšœO˜UJšœ˜—Jš˜Jšœœ|˜Jšœ ˜—Jšœ ˜—J˜Jšœ ˜ Jšœ"˜"Jšœ ˜Jšœ˜Jšœ ˜ Jš˜Jšœ ˜ J˜—J˜š Ÿ œœœ œ œœ˜XJšœœ@˜QJšœœœœ7˜ZJšœ"˜&J˜—J˜šŸœœœœ)œ œœ˜ušœœ˜šœ˜˜˜J˜SJšœœœ!œ˜=J˜YJšœœœ!œ˜=J˜——Jšœœ˜Jšœœ˜—Jšœn˜s˜J˜——Jšœœ˜ Jšœœ ˜LJ˜Jšœ œœ˜Jšœ#œ2 ˜rJš ™J˜ Jšœ œ˜˜=šœœ˜8Jšœ"œ˜+—J˜—Jšœ œœœ˜Jš ™˜=šœ˜Jšœ(œ˜1—J˜—Jšœ œœœ˜Jš %™%Jšœ(˜(J˜J˜—JšŸ™J˜š Ÿ œœ œœ œœ  ˜RJšœœœQ˜bJšœœœ˜*J˜-Jšœœœœ˜/J˜Jšœ˜ Jšœ˜J˜—š Ÿ œœœ&œœœ˜XJšœ œ˜šœ9™@J™1Jšœ œ™+J™CJšœ™—Jšœ$œe˜J˜ šœ9˜@Jšœœ1˜:J˜1Jšœ œ˜+Jšœ œœ˜@˜,Jšœœ˜—Jšœ˜—Jšœ˜ J˜J˜—šŸœ œœ œ˜PJš œœ œœœœ˜9J˜——™š Ÿœ œ œœœ œ˜sJšœœœ˜+Jšœ œ˜%Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœœ˜Jšœœ˜Jšœœœ˜šŸœœ˜$Jšœœ-˜DJšœœœ˜Jšœœ)œœ!˜YJ•StartOfExpansion/[atom: ATOM, prop: REF ANY, val: REF ANY]šœSœ œ˜pJš œœœ œœ˜*J˜]Jšœ˜š˜šŸ œœ$œœ˜HJ˜0J˜š˜Jšœ œœ˜Jšœœœœ œœœ˜Ršœ˜Jšœ'œœ˜BJšœ ÚœL™§Jšœ ˜Jšœ#˜#J˜—Jšœ˜Jšœ˜—J˜—šŸœœœ œ ˜BJšœœ˜!Jšœœ˜J˜Jšœ œ ˜Jšœ˜Jšœ" a˜ƒJšœH˜HJšœ˜Jšœœ˜8Jšœl 7˜£šœ™Jš œ œ œ œœ7™iJ™J™—J˜—Jšœœ˜J˜Jšœ\˜\Jš œœœ œœ˜*Jšœ!˜!šœ œ r˜œJšœ ˜¬Jšœ˜Jšœ˜—Jšœ œœ ˜Jšœ!˜#Jšœ˜šœ˜Jšœ ˜ šœ˜Jšœ œ˜Jš ˜ Jšœœ ˜—Jš˜Jšœœ˜Jšœ˜—š˜Jš œœœœœ ˜HJš œœœœ ˜QJš œœœœœ œ ˜„Jšœ ˜ Jš˜Jšœœ˜Jšœ˜—J˜ šœ'œ ˜MJšœ‘˜‘Jšœ˜Jšœ˜J˜—šœ˜Jšœœ˜#Jšœ€˜€Jšœ#˜#J˜—JšœQ 7˜ˆJšœœ˜ Jšœ˜Jšœ˜—Jšœ˜—J™J˜'Jšœ ˜J˜—J˜š Ÿœœ œ œœœ˜@Jšœœ˜Jšœ œœ˜Jšœ œœ˜Jšœ œ˜Jšœ(˜(Jšœœœ˜-š˜J˜Jšœ#˜#Jšœ ˜ šœ ˜Jšœ˜Jšœ œ˜Jšœœ œ ˜0Jšœ ˜ Jšœ˜šœ˜Jšœ œœ €˜šJšœ œ˜Jšœ œ˜Jšœ˜—Jšœ œ˜šœ˜ Jšœ œ˜Jšœ œ˜Jšœ ˜ Jšœ 6˜9—J˜—Jšœ˜—Jšœ ˜J˜——šœ ™ JšŸ œœœœœœœ œœ˜aJ˜šŸ œœ œ œLœœœœœ œ˜¶š˜Jšœœœ2˜O—Jšœ œ˜Jšœ&œ˜<šœ'˜.Jšœ%˜)—Jšœ˜JšœM˜Mšœ œ˜J˜'—š˜Jšœ œœ(˜>Jšœ3˜3J˜—Jšœ˜J˜—šŸ œœ œ6œœœœœ ˜§Jšœœ œ ˜J˜Jšœœ˜šœ&œ˜.šœœœ  ˜UJšœœ˜ š œœœœœ œ˜_Jšœ ˜ Jšœ˜ Jšœ˜Jšœ˜—J˜ J˜—šœ˜Jšœ1˜1šœ;˜;šœ˜J˜/˜Jš œ œœœœ [˜Žšœ œ˜Jšœ˜Jšœ1˜1Jš˜Jšœ˜—J˜.J˜—Jšœ˜&—Jš ˜ Jšœ˜J˜—J˜—J˜—šœ œœWœ˜‚šœœ˜J˜J˜!J˜&J˜/J˜$Jšœœ˜—Jš œ œœ5œ œœ˜kJš ˜ Jšœ˜Jšœ˜—šœ œ˜JšœœAœ˜`Jšœœœ 6˜mJšœ ˜J˜—šœ œœ˜Jšœœ5˜NJšœœ"œ˜FJšœ˜—Jšœ#˜#Jšœœ*˜@Jšœ˜—J˜—™JšŸ œœœœ˜"J˜šŸ œ#œ  ˜FJšœ2œ˜9Jšœ œ!˜2J˜—J˜J˜1—J˜Jšœ ˜J˜J˜qJ˜š2™2J™”Jšœ Ïr™—šZ™ZJšœ ¢™$—š0™0Jšœ ¢ œ™)—™0Jšœ ¢™—™-Jšœ ¢™+—™.Jšœ ¢1™=—J™™.Jšœ ¢™—™.Jšœ ¢™—™-Jšœ ¢6™B—J™™.Jšœ ¢™—™/Jšœ ¢Mœ¢œ¢œ™¾—J™J™J™J™J™J™J™J™J™™,Jšœ ¢ ™—™,Jšœ ¢ œ™%—J™—…—R¢xÉ