-- File: ExecSS.mesa -- edited by Levin, January 27, 1981 11:59 AM. -- edited by Brotz, May 4, 1981 4:36 PM. -- edited by Schroeder, February 6, 1981 2:49 PM. DIRECTORY Ascii, AltoFileDefs, BcdDefs, BcdOps, ControlDefs, crD: FROM "CoreDefs", DiskKDDefs, Editor, exD: FROM "ExceptionDefs", FrameDefs, FrameOps, gsD: FROM "GlobalStorageDefs", inD: FROM "InteractorDefs", intCommon: FROM "intCommon", IODefs, KeyDefs, LaurelExecDefs, LaurelExecImpDefs, lmD: FROM "LaurelMenuDefs", LoaderOps, lsD: FROM "LaurelStateDefs", NameInfoSpecialDefs, NameInfoDefs, opD: FROM "OperationsDefs", OsStaticDefs, ovD: FROM "OverviewDefs", ProcessDefs, ProcessOps, PSBDefs, RetrieveDefs, SegmentDefs, Storage, StreamDefs, String, SwapperOps, TrapDefs, vmD: FROM "VirtualMgrDefs"; ExecSS: PROGRAM IMPORTS crD, DiskKDDefs, Editor, exD, FrameDefs, FrameOps, inD, intC: intCommon, IODefs, KeyDefs, LaurelExecImpDefs, lmD, LoaderOps, lsD, NameInfoDefs, NameInfoSpecialDefs, opD, ProcessDefs, RetrieveDefs, SegmentDefs, Storage, String, SwapperOps, TrapDefs, vmD EXPORTS inD, LaurelExecDefs, LaurelExecImpDefs, StreamDefs SHARES SegmentDefs, StreamDefs, vmD = BEGIN OPEN LaurelExecImpDefs; RunCommand: PUBLIC PROCEDURE [hp: inD.HousePtr, confirmed: BOOLEAN] = BEGIN OPEN inD; bcdname: STRING _ [maxBracketStringLength]; cmMnp _ intC.cmTextNbr; inD.StopBlinkingCaret[]; exD.ClearExceptionsRegion[]; lmD.ChangeEditorMenu[run]; inD.MakeCommandsCallable[FALSE]; BEGIN IF ~confirmed AND ~ConfirmBrackets[hp: intC.runBracketsHouse, fileExtension: ".laurel."L] THEN GO TO Done; String.AppendString[bcdname, intC.runBracketsHouse.text]; IF LocalizeBcd[bcdname] THEN BEGIN SpliceInIODefs[]; ProcessDefs.Detach[FORK DoRunBcd[bcdname, hp]]; RETURN END; EXITS Done => NULL; END; Cleanup[hp]; END; -- of RunCommand -- DoRunBcd: PROCEDURE [bcdname: STRING, hp: inD.HousePtr] = BEGIN OPEN String; VitalSigns: TYPE = RECORD [processes, modules, pages: CARDINAL]; GetVitalSigns: PROCEDURE RETURNS [vitalSigns: VitalSigns] = BEGIN OPEN ProcessOps, SegmentDefs; CheckSegment: PROCEDURE [seg: SegmentHandle] RETURNS [BOOLEAN] = BEGIN inc: CARDINAL _ 0; WITH s: seg SELECT FROM data => SELECT s.type FROM IN [FrameDS .. BitmapDS], gsD.storageType => NULL; ENDCASE => inc _ s.pages; file => -- deal with AltoLoader bug that doesn't flush code after errors -- only works for single file bcds IF s.file = runFile AND s.class = code AND s.lock = 0 THEN DeleteFileSegment[@s] ELSE IF s.lock > 0 AND s.file ~= lsD.stateFile THEN inc _ s.pages; ENDCASE; vitalSigns.pages _ vitalSigns.pages + inc; RETURN[FALSE] END; -- of CheckSegment -- CountModule: PROCEDURE [f: ControlDefs.GlobalFrameHandle] RETURNS [BOOLEAN] = BEGIN vitalSigns.modules _ vitalSigns.modules + 1; RETURN[FALSE] END; -- of CountModule -- NameInfoSpecialDefs.CleanUp[]; vitalSigns _ [0, 0, 0]; -- FOR p: PSBDefs.ProcessHandle _ FirstProcess^, p + SIZE[PSBDefs.PSB] DO -- IF p.state = alive THEN vitalSigns.processes _ vitalSigns.processes + 1; -- IF p = LastProcess^ THEN EXIT; -- ENDLOOP; [] _ DiskKDDefs.CloseDiskKD[]; [] _ SwapperOps.EnumerateObjects[segment, LOOPHOLE[CheckSegment]]; -- [] _ FrameDefs.EnumerateGlobalFrames[CountModule]; END; Wizard: PROCEDURE RETURNS [BOOLEAN] = BEGIN userName: STRING; mbr: NameInfoDefs.Membership; SELECT RetrieveDefs.MailboxState[intC.retrieveHandle] FROM badName, badPwd, cantAuth => RETURN[FALSE]; ENDCASE; userName _ Storage.String[intC.user.name.length+intC.user.registry.length+1]; String.AppendString[userName, intC.user.name]; String.AppendChar[userName, '.]; String.AppendString[userName, intC.user.registry]; mbr _ NameInfoDefs.IsMemberClosure["Wizards.ms"L, userName]; NameInfoSpecialDefs.CleanUp[]; Storage.FreeString[userName]; RETURN[mbr = yes]; END; -- of Wizard -- RunBcd: PROCEDURE = BEGIN OPEN FrameDefs, LoaderOps, SegmentDefs; cm: ControlDefs.ControlModule; bcd: BcdOps.BcdBase; bcdseg: FileSegmentHandle; OurLoad: PROCEDURE RETURNS [worked: BOOLEAN] = -- This is derived from AltoLoader.Load and incorporates some bug fixes -- and some optimizations. BEGIN bcdseg _ NewFileSegment[runFile, 1, 1, Read]; BEGIN pages: CARDINAL; worked _ FALSE; MakeSwappedIn[bcdseg, DefaultMDSBase, HardUp ! SegmentFault => GO TO bogus]; bcd _ FileSegmentAddress[bcdseg]; IF bcd.versionIdent # BcdDefs.VersionID OR bcd.definitions THEN {Unlock[bcdseg]; GO TO bogus} ELSE IF (pages _ bcd.nPages) > 1 THEN BEGIN Unlock[bcdseg]; MoveFileSegment[bcdseg, 1, pages]; MakeSwappedIn[bcdseg, DefaultMDSBase, HardUp]; bcd _ FileSegmentAddress[bcdseg]; END; worked _ TRUE; EXITS bogus => DeleteFileSegment[bcdseg]; END; END; -- of OurLoad -- OurUnload: PROCEDURE = BEGIN Unlock[bcdseg]; DeleteFileSegment[bcdseg]; END; -- of OurUnload -- runFile _ NewFile[s, Read, OldFileOnly ! FileNameError => {Gripe[exD.fileNotFound]; GO TO out}]; LockFile[runFile]; IF ~OurLoad[ ! InsufficientVM => {Gripe[exD.programTooLarge]; GO TO out}] THEN GO TO cantExecute; cm _ LoaderOps.New[bcd, TRUE, FALSE ! BadCode => GO TO cantExecute; String.StringBoundsFault => {Gripe[exD.illegalBrackets]; GO TO out}; VersionMismatch => {Gripe[exD.versionMismatch, name]; GO TO out}; FileNotFound => {Gripe[exD.requiredFileMissing, name]; GO TO out}; InsufficientVM => {Gripe[exD.suggestRestart]; OurUnload[]; GO TO out} ]; IF cm = ControlDefs.NullControl THEN GO TO cantExecute; FrameOps.Start[cm ! UNWIND => UnNewConfig[cm.frame]]; UnNewConfig[cm.frame]; EXITS cantExecute => Gripe[exD.bcdUnexecutable]; out => NULL; END; -- of RunBcd -- s: STRING _ [100]; originalVitalSigns, newVitalSigns: VitalSigns; runFile: SegmentDefs.FileHandle _ NIL; AppendString[s, bcdname]; [] _ Storage.Prune[]; originalVitalSigns _ GetVitalSigns[]; clientPages _ clientWords _ 0; RunBcd[ ! exD.SysBugSignal => REJECT; ANY => { signal, signalArg: CARDINAL; [signalArg, signal] _ SIGNAL TrapDefs.SendMsgSignal; AppendString[s, " got an uncaught signal: "L]; AppendOctal[s, signal]; AppendString[s, ", arg: "L]; AppendOctal[s, signalArg]; exD.SysBug[exD.nil, s]}]; SpliceOutIODefs[]; newVitalSigns _ GetVitalSigns[]; IF newVitalSigns.modules ~= originalVitalSigns.modules OR newVitalSigns.pages ~= originalVitalSigns.pages -- OR newVitalSigns.processes # originalVitalSigns.processes -- OR clientPages # 0 OR clientWords # 0 THEN BEGIN AppendString[s, " has put a hole in me!"L]; AppendString[s, " (Fluids leaking: "L]; -- IF newVitalSigns.processes > originalVitalSigns.processes+2 THEN AppendChar[s, 'P]; IF newVitalSigns.modules ~= originalVitalSigns.modules THEN AppendChar[s, 'M]; IF newVitalSigns.pages ~= originalVitalSigns.pages THEN AppendChar[s, 'L]; IF clientPages # 0 OR clientWords # 0 THEN AppendChar[s, 'S]; AppendChar[s, ')]; IF Wizard[] THEN BEGIN clock: CARDINAL _ inD.realTimeClock^; exD.DisplayExceptionString[s]; UNTIL inD.realTimeClock^ - clock > 125 DO ENDLOOP; exD.DisplayExceptionStringOnLine[" ... but I feel much better now."L, 2]; END ELSE Movie[s]; END; IF runFile ~= NIL THEN {SegmentDefs.UnlockFile[runFile]; SegmentDefs.ReleaseFile[runFile]}; Cleanup[hp]; END; -- of DoRunBcd -- Cleanup: PROCEDURE [hp: inD.HousePtr] = BEGIN intC.keystream.reset[intC.keystream]; [] _ Storage.Prune[]; inD.IndicateCommandFinished[hp]; inD.MakeCommandsCallable[TRUE]; IF inD.CaretIsBlinking[] THEN inD.SetCaretBlinking[intC.target.point, cmMnp]; END; -- of Cleanup -- LocalizeBcd: PROCEDURE [bcdname: STRING] RETURNS [worked: BOOLEAN] = BEGIN OPEN String; error: ovD.ErrorCode; errorString: STRING; dotLaurel: STRING _ ".laurel"L; hasExtension: BOOLEAN _ FALSE; bcdNameLength: CARDINAL _ bcdname.length; file: crD.UFileHandle; worked _ FALSE; IF bcdNameLength = 0 THEN GO TO BadFileName; FOR i: CARDINAL IN [0 .. bcdNameLength) DO IF bcdname[i] = '. THEN {hasExtension _ TRUE; EXIT}; ENDLOOP; IF bcdname[0] = '[ THEN BEGIN -- remote file; retrieve it localFile: STRING _ [AltoFileDefs.FilenameChars]; OverwriteOK: PROCEDURE RETURNS [BOOLEAN] = BEGIN exD.DisplayExceptionLine[exD.remoteFileWillOverwrite, 1]; RETURN [inD.Confirm[2]]; END; --OverwriteOK-- FOR i: CARDINAL _ bcdNameLength, i - 1 UNTIL i = 0 DO SELECT bcdname[i - 1] FROM ';, '! => bcdNameLength _ i - 1; '], '> => BEGIN ssd: SubStringDescriptor _ [base: bcdname, offset: i, length: bcdNameLength - i]; AppendSubString[localFile, @ssd]; IF ~hasExtension THEN BEGIN ENABLE StringBoundsFault => GO TO BadFileName; trailer: STRING _ [10]; trailerSSD: SubStringDescriptor _ [base: bcdname, offset: bcdNameLength, length: bcdname.length - bcdNameLength]; AppendSubString[trailer, @trailerSSD]; bcdname.length _ bcdNameLength; AppendString[bcdname, dotLaurel]; AppendString[bcdname, trailer]; AppendString[localFile, dotLaurel]; END; EXIT END; ENDCASE => NULL; REPEAT FINISHED => GO TO BadFileName; ENDLOOP; exD.DisplayExceptionLine[exD.retrievingRemoteFile, 1]; [error, , errorString] _ opD.Copy[bcdname, localFile, OverwriteOK]; IF error # ovD.ok THEN BEGIN Gripe[exD.nil, "Error during retrieval: "L, errorString]; IF errorString#NIL THEN opD.FreeErrorString[errorString]; END ELSE exD.ClearExceptionsRegion[]; bcdname.length _ 0; AppendString[bcdname, localFile]; worked _ error = ovD.ok; END ELSE BEGIN IF ~hasExtension THEN AppendString[bcdname, dotLaurel ! StringBoundsFault => GO TO BadFileName]; [error, file] _ crD.OpenFile[intC.user, bcdname, read]; SELECT error FROM ovD.ok => [] _ crD.CloseFile[file]; ovD.fileNotFound => IF Storage.StringLength[intC.runPath] ~= 0 AND intC.runPath[0] = '[ THEN BEGIN s: STRING _ [inD.maxBracketStringLength]; AppendString[s, intC.runPath]; AppendString[s, bcdname]; exD.DisplayExceptionStringOnLine [bcdname, 1 ! exD.ExceptionLineOverflow => CONTINUE]; exD.AppendStringToExceptionLine [" not found. Will retrieve "L, 1 ! exD.ExceptionLineOverflow => CONTINUE]; exD.AppendStringToExceptionLine[s, 1 ! exD.ExceptionLineOverflow => CONTINUE]; RETURN[inD.Confirm[2] AND LocalizeBcd[s]]; END; ovD.illegalFilename => GO TO BadFileName; ovD.fileInUse => GO TO Unrunnable; ENDCASE; worked _ TRUE; END; IF worked THEN BEGIN -- bcdname is local now. Refresh brackets without .laurel. bracketsHouse: inD.HousePtr = intC.runBracketsHouse; bcdnameSansDotLaurel: STRING _ [inD.maxBracketStringLength]; ssdDotLaurel: SubStringDescriptor _ [base: dotLaurel, offset: 0, length: dotLaurel.length]; ssdLocalFileTrailer: SubStringDescriptor _ [base: bcdname, offset: bcdname.length - dotLaurel.length, length: dotLaurel.length]; AppendString[bcdnameSansDotLaurel, bcdname]; IF bcdname.length > dotLaurel.length AND EquivalentSubString[@ssdDotLaurel, @ssdLocalFileTrailer] THEN bcdnameSansDotLaurel.length _ ssdLocalFileTrailer.offset; IF ~EquivalentString[bracketsHouse.text, bcdnameSansDotLaurel] THEN BEGIN bracketsHouse.text.length _ 0; AppendString[bracketsHouse.text, bcdnameSansDotLaurel]; bracketsHouse.houseRefresher[bracketsHouse]; END; END; EXITS BadFileName => Gripe[exD.illegalBrackets]; Unrunnable => Gripe[exD.bcdUnexecutable]; END; -- of LocalizeBcd -- Gripe: PROCEDURE[exception: exD.Exception, s1: STRING _ NIL, s2: STRING _ NIL] = BEGIN s: STRING _ [120]; IF exception # exD.nil THEN exD.AppendExceptionString[exception, s]; IF s1 ~= NIL THEN String.AppendString[s, s1]; IF s2 ~= NIL THEN String.AppendString[s, s2]; exD.DisplayExceptionStringOnLine[s, 1]; exD.DisplayExceptionLine[exD.runCanceled, 2]; exD.FlashExceptionsRegion[]; END; -- of Gripe -- MakeMenuCommandCallable: PUBLIC PROCEDURE [menuCommand: LaurelExecDefs.MenuCommand, callable: BOOLEAN _ TRUE] = -- Sets the callable property of the Laurel screen command menuCommand to be the value of -- the input paramter callable. BEGIN SELECT menuCommand FROM user => intC.userCommandHouse.callable _ callable; newMail => intC.newMailCommandHouse.callable _ callable; mailFile => intC.mailFileCommandHouse.callable _ callable; quit => intC.quitCommandHouse.callable _ callable; display => intC.displayCommandHouse.callable _ callable; hardcopy => intC.hardcopyCommandHouse.callable _ callable; delete => intC.deleteCommandHouse.callable _ callable; undelete => intC.undeleteCommandHouse.callable _ callable; moveTo => intC.moveToCommandHouse.callable _ callable; newForm => intC.newFormCommandHouse.callable _ callable; answer => intC.answerCommandHouse.callable _ callable; forward => intC.forwardCommandHouse.callable _ callable; get => intC.getCommandHouse.callable _ callable; put => intC.putCommandHouse.callable _ callable; copy => intC.copyCommandHouse.callable _ callable; run => intC.runCommandHouse.callable _ callable; deliver => intC.deliverCommandHouse.callable _ callable; ENDCASE => exD.SysBug[]; END; -- of MakeMenuCommandCallable -- -- Initialization Procedures -- savedEOMstring: STRING; SpliceExecutiveIntoEditor: PUBLIC PROCEDURE = BEGIN target: inD.TextSelectionPtr = @intC.target; savedEOMstring _ cmMnp.endString; cmMnp.endString _ ""; IF ~cmMnp.haveMessage THEN BEGIN -- initialize the composed message. Editor.SetHighWaterMark[0]; Editor.RefreshSoThatFirstCharStartsLine[firstChar: 0, firstLine: cmMnp.lines, mnp: cmMnp]; cmMnp.haveMessage _ TRUE; END; IF target.end ~= 0 THEN Editor.DeUnderlineSelection[target, target]; Editor.InitializeSelection[target]; intC.actionPoint _ 0; intC.composedMessageEdited _ FALSE; intC.commandMode _ FALSE; IF intC.runCommandMode THEN BEGIN target.point _ vmD.GetMessageSize[cmMnp.message]; [] _ Editor.MakeCharIndexVisible[target.point, cmMnp]; Editor.RefreshEndOfMessage[cmMnp]; END ELSE BEGIN Editor.ResetBuffers[cmMnp]; Editor.SwapMessageWithDeletionBuffer[cmMnp]; Editor.SetHighWaterMark[0]; Editor.RefreshSoThatFirstCharStartsLine[0, cmMnp.lines, cmMnp]; intC.runCommandMode _ TRUE; END; intC.commandType _ get; END; -- of SpliceExecutiveIntoEditor -- SpliceExecutiveOutOfEditor: PUBLIC PROCEDURE = BEGIN point: ovD.CharIndex _ intC.target.point; intC.target _ inD.TextSelection[cmMnp, point, point, point, char, FALSE]; intC.commandMode _ TRUE; inD.StopBlinkingCaret[]; cmMnp.endString _ savedEOMstring; Editor.RefreshEndOfMessage[cmMnp]; END; -- of SpliceExecutiveOutOfEditor -- ks: StreamDefs.KeyboardHandle; ds: StreamDefs.DisplayHandle; SpliceInIODefs: PROCEDURE = BEGIN OPEN StreamDefs; s: StreamHandle _ Storage.Node[SIZE[Other StreamObject]]; -- not Keyboard s^ _ [ reset: ResetKS, get: GetKS, putback: PutBackKS, put: PutKS, endof: EndOfKS, destroy: DestroyKS, link: NIL, body: Keyboard[in: , out: , buffer: ] -- these are never used ]; ks _ LOOPHOLE[s]; ds _ Storage.Node[SIZE[Display StreamObject]]; ds^ _ [ reset: ResetDS, get: GetDS, putback: PutBackDS, put: PutDS, endof: EndOfDS, destroy: DestroyDS, link: NIL, body: Display[ clearCurrentLine: ClearCurrentLineDS, clearLine: ClearLineDS, clearChar: ClearCharDS, type: , data: ] ]; IF intC.editorType = modeless THEN [] _ KeyDefs.ChangeKey[LF, [FALSE, LOOPHOLE[Ascii.LF], LOOPHOLE[Ascii.LF]]]; IODefs.SetInputStream[ks]; IODefs.SetOutputStream[ds]; InitializeExecIO[]; END; -- of SpliceInIODefs -- GetDefaultDisplayStream: PUBLIC PROCEDURE RETURNS [StreamDefs.DisplayHandle] = -- This hack procedure is needed to avoid UnboundProcedure when StreamIO is started. BEGIN RETURN[NIL] END; -- of GetDefaultDisplayStream -- SpliceOutIODefs: PROCEDURE = BEGIN IF intC.editorType = modeless THEN [] _ KeyDefs.ChangeKey[LF, [FALSE, LOOPHOLE[Editor.insertDeletionCode], LOOPHOLE[Editor.insertDeletionCode]]]; FinalizeExecIO[]; Storage.Free[ks]; Storage.Free[ds]; END; ShortenTypeScript: PUBLIC PROCEDURE = BEGIN composeMessage: vmD.ComposeMessagePtr = LOOPHOLE[cmMnp.message]; charMap: POINTER TO vmD.CMOCharMapTable = composeMessage.charMap; line: inD.LinePtr; nDelete: CARDINAL _ 0; FOR i: vmD.PageNumber IN [0 .. 10) DO nDelete _ nDelete + charMap[i].count; ENDLOOP; vmD.DeleteRangeInMessage[[0, nDelete, composeMessage]]; intC.target.point _ vmD.GetMessageSize[composeMessage]; FOR line _ cmMnp.lines, line.nextLine UNTIL line = NIL DO line.firstCharIndex _ line.firstCharIndex - nDelete; ENDLOOP; Editor.SetHighWaterMark[intC.target.point]; END; -- of ShortenTypeScript -- END. -- of ExecSS -- z20461x0(635)\f1