-- Copyright (C) 1982, 1984, 1985 by Xerox Corporation. All rights reserved. -- CommandsAndSuch.mesa, HGM, 20-Sep-85 0:08:54 -- From Othello's VolumeInitCommandImpl of 30-Sep-82 13:48:35. DIRECTORY Ascii USING [CR], Boot USING [mdsiGerm], Environment USING [bytesPerWord, Long], Format USING [HostNumber, StringProc], Frame USING [Free, ReadLocalWord], Heap USING [systemZone], Inline USING [LowHalf], MStoreImpl USING [countFree], OthelloDefs USING [ BlinkDisplay, CommandProcessor, ConfirmType, EchoNoEcho, NewLine, ReadChar, WriteChar, WriteLine, WriteLongNumber, WriteOctal, WriteString], OthelloOps USING [ BootFileType, GetTimeFromTimeServer, IsTimeValid, SetProcessorTime, TimeServerError], OthelloForgot USING [ EraseTTYChar, ResetAbort, SmashPassword, WaitForConnection, WriteLongOctal], PilotMP USING [cTimeNotAvailable], PrincOps USING [frameSizeMap, LocalFrameHandle, LocalOverhead], ProcessorFace USING [SetMP, mp], Process USING [Detach, Pause, SecondsToTicks], Runtime USING [GetBuildTime], SDDefs USING [SD, sSystemDate], SpecialRuntime USING [GetCurrentSignal], SpecialSpace USING [realMemorySize], String USING [ AppendChar, AppendCharAndGrow, AppendDecimal, AppendLongDecimal, AppendLongNumber, AppendString, EquivalentSubString, InvalidNumber, StringBoundsFault, StringToNumber, SubStringDescriptor, UpperCase], System USING [ AdjustGreenwichMeanTime, GetGreenwichMeanTime, GetLocalTimeParameters, GreenwichMeanTime, gmtEpoch, HostNumber, localHostNumber, LocalTimeParameters, SetLocalTimeParameters], Time USING [Append, defaultTime, Invalid, Pack, Unpack, Unpacked], Version USING [Append], CpuIdle USING [GetSmoothedCpuUtilization], BootFileInfoNoDisk USING [], MicrocodeVersion USING [VERSION, VersionResult]; CommandsAndSuch: PROGRAM IMPORTS Format, Frame, Heap, Inline, OthelloDefs, OthelloOps, OthelloForgot, Process, ProcessorFace, Runtime, SpecialRuntime, SpecialSpace, String, System, Time, Version, CpuIdle, MicrocodeVersion EXPORTS OthelloDefs, OthelloForgot, BootFileInfoNoDisk SHARES MStoreImpl = BEGIN z: UNCOUNTED ZONE = Heap.systemZone; startTime: System.GreenwichMeanTime ¬ System.gmtEpoch; MyNameIs: PUBLIC SIGNAL [myNameIs: STRING, myHelpIs: STRING] = CODE; AbortingCommand: PUBLIC ERROR [reason: LONG STRING, reasonOne: LONG STRING ¬ NIL] = CODE; IndexTooLarge: PUBLIC ERROR = CODE; Question: PUBLIC SIGNAL = CODE; TryAgain: PUBLIC SIGNAL = CODE; Quit: SIGNAL = CODE; BS: CHARACTER = 10C; ControlA: CHARACTER = 'A - 100B; ControlP: CHARACTER = 'P - 100B; ControlW: CHARACTER = 'W - 100B; CR: CHARACTER = 15C; DEL: CHARACTER = 177C; ESC: CHARACTER = 33C; SP: CHARACTER = ' ; NUL: CHARACTER = 0C; CommandProcessor: TYPE = OthelloDefs.CommandProcessor; -- ~~~~~~~~~~~~~~~~~~~~~~~~ -- Commands -- ~~~~~~~~~~~~~~~~~~~~~~~~ CurrentComand: SIGNAL RETURNS [ proc: PROCEDURE [index: CARDINAL], index: CARDINAL] = CODE; ForAllCommandProcs: PROCEDURE [P: PROC[STRING]] = { FOR c: POINTER TO CommandProcessor ¬ commands, c.next WHILE c # NIL DO FOR i: CARDINAL IN [0..LAST[CARDINAL]) DO ENABLE CurrentComand => RESUME[c.proc, i]; c.proc[i ! MyNameIs => {P[myNameIs]; CONTINUE}; IndexTooLarge => EXIT]; ENDLOOP ENDLOOP}; Help: PROCEDURE = { WidthProc: PROCEDURE [s: STRING] = {tabWidth ¬ MAX[tabWidth, s.length]}; tabWidth: CARDINAL ¬ 0; SIGNAL MyNameIs[myNameIs: "Help"L, myHelpIs: "Type this table"L]; ForAllCommandProcs[WidthProc]; tabWidth ¬ tabWidth + 4; FOR c: POINTER TO CommandProcessor ¬ commands, c.next WHILE c # NIL DO FOR i: CARDINAL IN [0..LAST[CARDINAL]) DO c.proc[i ! MyNameIs => { OthelloDefs.WriteString[myNameIs]; THROUGH [myNameIs.length..tabWidth) DO OthelloDefs.WriteChar[' ] ENDLOOP; OthelloDefs.WriteLine[myHelpIs]; CONTINUE}; IndexTooLarge => EXIT]; ENDLOOP ENDLOOP; OthelloDefs.WriteLine[ "In General, Del will abort current command, ? will explain options"L]}; BuiltinCommands: PROCEDURE [index: CARDINAL] = { SELECT index FROM 0 => { SIGNAL MyNameIs[myNameIs: "Info"L, myHelpIs: "Retype startup Info"L]; PrintHerald[]; PrintMemorySize[]; PrintPIDs[]; PrintBootFileDate[]; PrintGermDate[]; PrintMicrocodeInfo[]; OthelloDefs.WriteString["Current time"L]; WriteTime[Time.defaultTime, TRUE]; PrintTimeInfo[]; OthelloDefs.NewLine[]; }; 1 => { SIGNAL MyNameIs[myNameIs: "Quit"L, myHelpIs: "Break the connection"L]; Confirm[]; SIGNAL Quit; }; 2 => { SIGNAL MyNameIs[myNameIs: "Time"L, myHelpIs: "Time of day"L]; OthelloDefs.WriteString["Current time"L]; WriteTime[Time.defaultTime, TRUE]; PrintTimeInfo[]; OthelloDefs.NewLine[]; }; 3 => Help[]; ENDCASE => ERROR IndexTooLarge}; RegisterCommandProc: PUBLIC PROCEDURE [ commandProc: POINTER TO CommandProcessor] = { commandProc.next ¬ commands; commands ¬ commandProc}; commands: POINTER TO CommandProcessor ¬ @helpCommandProcessor; helpCommandProcessor: CommandProcessor ¬ [BuiltinCommands, NIL]; -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Basic command processing -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CollectCommand: PROCEDURE RETURNS [ p: PROCEDURE [index: CARDINAL], index: CARDINAL] = { ExplainOptions: PROCEDURE = { first: BOOLEAN ¬ TRUE; OthelloDefs.WriteChar['?]; IF userString.length # 0 THEN { P: PROCEDURE [s: STRING] = { IF HeadMatch[s, userString.length] THEN { OthelloDefs.WriteString[IF first THEN "\rCurrent Options Are: "L ELSE ", "L]; OthelloDefs.WriteString[s]; first ¬ FALSE}}; ForAllCommandProcs[P]}; IF first THEN { -- Didn't match... tell all P: PROCEDURE [s: STRING] = { IF ~first THEN OthelloDefs.WriteString[", "L]; OthelloDefs.WriteString[s]; first ¬ FALSE}; OthelloDefs.WriteString["\rValid Commands Are: "L]; ForAllCommandProcs[P]}; OthelloDefs.WriteString["\r> "L]; OthelloDefs.WriteString[userString]}; FindAnswer: TYPE = RECORD [ SELECT how: * FROM none => NULL, many => NULL, one => [proc: PROCEDURE [index: CARDINAL], index: CARDINAL], ENDCASE]; FindPossibles: PROCEDURE RETURNS [ans: FindAnswer ¬ [none[]]] = { P: PROCEDURE [matchString: STRING] = { IF HeadMatch[matchString, head] THEN WITH ans SELECT FROM none => { ans ¬ [one[CurrentComand[].proc, CurrentComand[].index]]; UNTIL userString.length = matchString.length DO userString[userString.length] ¬ matchString[userString.length]; IF (userString.length ¬ userString.length + 1) = userString.maxlength THEN { OthelloDefs.WriteLine[" Command too long!"L]; ERROR TryAgain} ENDLOOP}; ENDCASE => { --ASSERT[head#0] FOR i : CARDINAL IN [head - 1..LAST[CARDINAL]) DO IF LowerCase[userString[i]] # LowerCase[matchString[i]] THEN { userString.length ¬ i; EXIT}; ENDLOOP; ans ¬ [many[]]}}; head: CARDINAL ¬ userString.length; IF head = 0 THEN RETURN; ForAllCommandProcs[P]; WHILE head # userString.length DO OthelloDefs.WriteChar[userString[head]]; head ¬ head + 1 ENDLOOP}; HeadMatch: PROCEDURE [matchString: STRING, head: CARDINAL] RETURNS [BOOLEAN] = { IF head > matchString.length THEN RETURN[FALSE]; FOR i: CARDINAL IN [0..head) DO IF LowerCase[userString[i]] # LowerCase[matchString[i]] THEN RETURN[FALSE] ENDLOOP; RETURN[TRUE]}; LowerCase: PROCEDURE [c: CHARACTER] RETURNS [CHARACTER] = { RETURN[IF c IN ['A..'Z] THEN c + ('a - 'A) ELSE c]}; userString: STRING = [100]; userString.length ¬ 0; OthelloDefs.WriteString["> "L]; DO c: CHARACTER = OthelloDefs.ReadChar[]; SELECT c FROM DEL => {OthelloDefs.WriteLine[" XXX"L]; ERROR TryAgain}; BS, ControlA => IF userString.length # 0 THEN OthelloForgot.EraseTTYChar[userString[userString.length ¬ userString.length - 1]]; ControlW => IF userString.length # 0 THEN DO OthelloForgot.EraseTTYChar[userString[userString.length ¬ userString.length - 1]]; IF userString.length=0 OR userString[userString.length - 1] = SP THEN EXIT ENDLOOP; '? => ExplainOptions[]; CR, SP => { ans: FindAnswer = FindPossibles[]; WITH theAns: ans SELECT FROM none => OthelloDefs.BlinkDisplay[]; many => NULL; one => RETURN[theAns.proc, theAns.index]; ENDCASE => ERROR}; ENDCASE => IF (userString.length ¬ userString.length + 1) = userString.maxlength THEN { OthelloDefs.WriteLine[" Command too long!"L]; ERROR TryAgain} ELSE OthelloDefs.WriteChar[userString[userString.length - 1] ¬ c]; ENDLOOP}; -- ~~~~~~~~~~~~~~~~~~~~~~~~ -- Utility-Type Functions -- ~~~~~~~~~~~~~~~~~~~~~~~~ Confirm: PUBLIC PROCEDURE [how: OthelloDefs.ConfirmType ¬ once] = { Nap: PROCEDURE = {FOR i: CARDINAL IN [0..LAST[CARDINAL]) DO ENDLOOP}; OthelloDefs.WriteString["Are you "L]; IF how = thrice THEN OthelloDefs.WriteString["still "L]; OthelloDefs.WriteString["sure? [y or n]: "L]; DO c: CHARACTER = OthelloDefs.ReadChar[]; SELECT c FROM 'y, 'Y, CR => {OthelloDefs.WriteLine["Yes"L]; EXIT}; 'n, 'N, DEL => {OthelloDefs.WriteLine["No"L]; ERROR TryAgain}; ENDCASE => OthelloDefs.BlinkDisplay[]; ENDLOOP; IF how = twice THEN {Nap[]; Confirm[thrice]}}; DebugAsk: PUBLIC PROCEDURE = { OthelloDefs.WriteString["\rType ControlP to muddle on........"L]; WHILE OthelloDefs.ReadChar[] # ControlP DO ENDLOOP; OthelloDefs.NewLine[]}; GetNameWithSpaces: PUBLIC PROCEDURE [prompt: STRING ¬ NIL, dest: POINTER TO LONG STRING] = BEGIN ENABLE UNWIND => spacesInStringOK ¬ FALSE; spacesInStringOK ¬ TRUE; GetName[prompt, dest]; spacesInStringOK ¬ FALSE; END; spacesInStringOK: BOOLEAN ¬ FALSE; GetName: PUBLIC PROCEDURE [ prompt: STRING ¬ NIL, dest: POINTER TO LONG STRING, how: OthelloDefs.EchoNoEcho ¬ echo, signalQuestion: BOOLEAN ¬ FALSE] = BEGIN first: BOOLEAN ¬ TRUE; EraseChar: PROCEDURE = { IF dest.length = 0 THEN RETURN; dest.length ¬ dest.length - 1; OthelloForgot.EraseTTYChar[IF how = echo THEN dest[dest.length] ELSE '*]; IF dest.length = 0 AND dest.maxlength > 20 THEN { z.FREE[dest]; dest­ ¬ z.NEW[StringBody[10]]; }}; CWriteC: PROCEDURE [c: CHARACTER] = {OthelloDefs.WriteChar[IF how = echo THEN c ELSE '*]}; CWriteString: PROCEDURE = { FOR i: CARDINAL IN [0..dest.length) DO CWriteC[dest[i]] ENDLOOP}; IF dest­ = NIL THEN dest­ ¬ z.NEW[StringBody[10]]; OthelloDefs.WriteString[prompt]; CWriteString[]; DO c: CHARACTER = OthelloDefs.ReadChar[]; SELECT TRUE FROM c = BS, c = ControlA => EraseChar[]; (c = SP AND ~spacesInStringOK), c = CR => {OthelloDefs.NewLine[]; RETURN}; c = DEL => {OthelloDefs.WriteLine[" XXX"L]; ERROR TryAgain}; c = ControlW => DO EraseChar[]; IF dest.length=0 THEN EXIT; SELECT dest[dest.length-1] FROM IN ['a..'z], IN ['A..'Z], IN ['0..'9] => LOOP; ENDCASE => EXIT; ENDLOOP; c = '? AND signalQuestion => { SIGNAL Question; OthelloDefs.WriteString[prompt]; CWriteString[]; LOOP}; c >= SP => { IF first THEN WHILE dest.length#0 DO EraseChar[] ENDLOOP; String.AppendCharAndGrow[dest, c, z]; CWriteC[dest[dest.length-1]]}; ENDCASE => OthelloDefs.BlinkDisplay[]; first ¬ FALSE; ENDLOOP; END; numberString: LONG STRING ¬ NIL; ReadNumber: PUBLIC PROCEDURE [ prompt: STRING, min, max, default: LONG CARDINAL ¬ LAST[LONG CARDINAL]] RETURNS [ans: LONG CARDINAL] = { DO IF default # LAST[LONG CARDINAL] THEN { IF numberString=NIL THEN numberString ¬ z.NEW[StringBody[15]]; numberString.length ¬ 0; String.AppendLongNumber[numberString, default, 10]}; OthelloDefs.WriteString[prompt]; OthelloDefs.WriteChar['[]; OthelloDefs.WriteLongNumber[min]; OthelloDefs.WriteString[".."L]; OthelloDefs.WriteLongNumber[max]; OthelloDefs.WriteString["]: "L]; GetName[dest: @numberString]; ans ¬ 0; FOR i: CARDINAL IN [0..numberString.length) DO IF numberString[i] NOT IN ['0..'9] THEN EXIT; ans ¬ 10*ans + numberString[i] - '0; REPEAT FINISHED => IF ans IN [min..max] THEN { z.FREE[@numberString]; RETURN}; ENDLOOP; OthelloDefs.WriteLine["Bad Number !"L]; ENDLOOP}; ReadShortNumber: PUBLIC PROCEDURE [ prompt: STRING, min, max, default: LONG CARDINAL] RETURNS [CARDINAL] = { RETURN[Inline.LowHalf[ ReadNumber[prompt, min, MIN[max, LONG[LAST[CARDINAL]]], default]]]}; Yes: PUBLIC PROCEDURE [s: STRING] RETURNS [BOOLEAN] = { OthelloDefs.WriteString[s]; DO SELECT OthelloDefs.ReadChar[] FROM 'Y, 'y, CR => {OthelloDefs.WriteLine["yes"L]; RETURN[TRUE]}; 'N, 'n, DEL => {OthelloDefs.WriteLine["no"L]; RETURN[FALSE]}; ENDCASE => OthelloDefs.WriteChar['?]; ENDLOOP}; -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Time munging -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- string format must be: bDD-MMM-YYbbHH:MM:SSbbZZTb PackedTimeFromString: PUBLIC PROCEDURE [ s: LONG STRING, justDate: BOOLEAN] RETURNS [t: System.GreenwichMeanTime] = { Empty: PROCEDURE [s: LONG STRING] RETURNS [BOOLEAN] = { RETURN[s = NIL OR s.length = 0]}; EquivalentChar: PUBLIC PROCEDURE [c1, c2: CHARACTER] RETURNS [BOOLEAN] = { RETURN[String.UpperCase[c1] = String.UpperCase[c2]]}; GetToken: PROCEDURE [storage: LONG STRING, s: LONG STRING, c: CARDINAL] RETURNS [is: CARDINAL] = { FOR is ¬ c, is + 1 UNTIL is >= s.length DO ch: CHARACTER = s[is]; SELECT ch FROM IN ['a..'z], IN ['A..'Z], IN ['0..'9] => String.AppendChar[storage, ch]; ':, '- => EXIT; -- terminator ' => IF ~Empty[storage] THEN EXIT; --terminating blank ENDCASE; ENDLOOP; RETURN[is + 1]}; DoIt: PROCEDURE [s: LONG STRING] RETURNS [t: System.GreenwichMeanTime] = { Get: PROCEDURE RETURNS [CARDINAL] = { s1.length ¬ 0; nextChar ¬ GetToken[s1, s, nextChar]; RETURN[s1.length]}; GetNumber: PROCEDURE RETURNS [CARDINAL] = { [] ¬ Get[]; RETURN[String.StringToNumber[s1, 10]]}; m: String.SubStringDescriptor ¬ [ base: "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"L, offset: NULL, length: 3]; s1: STRING = [3]; month: String.SubStringDescriptor ¬ [ base: s1, offset: 0, length: NULL]; time: Time.Unpacked ¬ [ 0, 0, 0, 0, 0, 0, 0, FALSE, System.GetLocalTimeParameters[]]; nextChar: CARDINAL ¬ 0; packIt: BOOLEAN ¬ TRUE; IF Empty[s] THEN RETURN[System.gmtEpoch]; time.day ¬ GetNumber[]; month.length ¬ Get[]; FOR i: CARDINAL IN [0..12) DO m.offset ¬ i*3; IF String.EquivalentSubString[@month, @m] THEN { time.month ¬ i; EXIT}; ENDLOOP; time.year ¬ GetNumber[]; time.year ¬ time.year + (IF time.year>68 THEN 1900 ELSE 2000); IF justDate THEN { time.hour ¬ 23; time.minute ¬ 59; time.second ¬ 59} ELSE { time.hour ¬ GetNumber[]; time.minute ¬ GetNumber[]; time.second ¬ GetNumber[]; IF Get[] # 0 THEN { zones: PACKED ARRAY [5..8] OF CHARACTER = ['E, 'C, 'M, 'P]; FOR i: CARDINAL IN [5..8] DO IF EquivalentChar[s1[0], zones[i]] THEN {time.zone.zone ¬ i; EXIT}; REPEAT FINISHED => time.zone.zone ¬ 0; -- GMT ENDLOOP; time.dst ¬ EquivalentChar[s1[1], 'D]; packIt ¬ FALSE}}; t ¬ Time.Pack[time, packIt]}; t ¬ DoIt[s ! String.InvalidNumber, String.StringBoundsFault, Time.Invalid => { t ¬ System.gmtEpoch; CONTINUE}]}; WriteTime: PROCEDURE [t: System.GreenwichMeanTime, showDay: BOOLEAN ¬ TRUE] = { days: ARRAY [0..7) OF STRING = [ "Monday"L, "Tuesday"L, "Wednesday"L, "Thursday"L, "Friday"L, "Saturday"L, "Sunday"L]; temps: STRING = [40]; Time.Append[temps, Time.Unpack[t], TRUE]; IF showDay THEN { OthelloDefs.WriteChar[' ]; OthelloDefs.WriteString[days[Time.Unpack[t].unpacked.weekday]]}; IF temps[0] # ' THEN OthelloDefs.WriteChar[' ]; OthelloDefs.WriteString[temps]}; PrintTimeInfo: PROCEDURE = BEGIN OthelloDefs.WriteString[", UP: "L]; PrintUpTime[System.GetGreenwichMeanTime[] -startTime]; OthelloDefs.WriteString[", CPU: "L]; OthelloDefs.WriteLongNumber[CpuIdle.GetSmoothedCpuUtilization[]]; OthelloDefs.WriteString["%"L]; OthelloDefs.WriteString["."L]; END; PrintUpTime: PROCEDURE [sec: LONG CARDINAL] = BEGIN min: LONG INTEGER; hours: LONG INTEGER; hours ¬ sec/3600; sec ¬ sec - hours*3600; min ¬ sec/60; sec ¬ sec - min*60; OthelloDefs.WriteLongNumber[hours]; OthelloDefs.WriteChar[':]; OthelloDefs.WriteLongNumber[min]; OthelloDefs.WriteChar[':]; OthelloDefs.WriteLongNumber[sec]; END; -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- The Big Loop -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Commander: PROCEDURE = BEGIN -- Krock. Give Login command time to connect up Process.Pause[Process.SecondsToTicks[10]]; IF startTime = System.gmtEpoch THEN startTime ¬ System.GetGreenwichMeanTime[]; DO ENABLE ABORTED, Quit => RETRY; OthelloForgot.SmashPassword[]; OthelloForgot.WaitForConnection[]; PrintHerald[]; IF ~OthelloOps.IsTimeValid[] THEN GetTime[] ELSE BEGIN IF startTime = System.gmtEpoch THEN startTime ¬ System.GetGreenwichMeanTime[]; END; DO TellError: PROCEDURE [s: LONG STRING] = BEGIN OthelloDefs.NewLine[]; OthelloDefs.WriteString[s]; END; p: PROCEDURE [index: CARDINAL]; i: CARDINAL; OthelloForgot.ResetAbort[]; [p, i] ¬ CollectCommand[ ! TryAgain => RETRY; AbortingCommand => {TellError[reason]; OthelloDefs.WriteLine[reasonOne]; LOOP}]; OthelloDefs.NewLine[]; BEGIN p[i ! MyNameIs => RESUME; ABORTED => GOTO Aborted; -- Beware of ML hangups AbortingCommand => { TellError[reason]; OthelloDefs.WriteLine[reasonOne]; CONTINUE}; String.StringBoundsFault => { TellError["String.StringBoundsFault"L]; DebugAsk[]; CONTINUE}; TryAgain => CONTINUE; Quit => REJECT; UNWIND => NULL; ANY => { signal: SIGNAL; args: PrincOps.LocalFrameHandle; size: CARDINAL; TellError["Uncaught Signal = "L]; [signal: signal, signalArgs: args] ¬ SIGNAL SpecialRuntime.GetCurrentSignal; OthelloForgot.WriteLongOctal[LOOPHOLE[signal]]; size ¬ PrincOps.frameSizeMap[Frame.ReadLocalWord[args].fsi] - SIZE[PrincOps.LocalOverhead]; OthelloDefs.WriteString[", msg = ["L]; FOR i: CARDINAL IN [0..size-1) DO OthelloDefs.WriteOctal[args[i]]; OthelloDefs.WriteString[", "L] ENDLOOP; OthelloDefs.WriteOctal[args[size-1]]; OthelloDefs.WriteChar[']]; Frame.Free[args]; DebugAsk[]; CONTINUE}]; EXITS Aborted => TellError["ABORTED\r"L]; END; ENDLOOP; ENDLOOP; END; -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Initialization Stuff -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GetTime: PROCEDURE = BEGIN timeTrys: CARDINAL ¬ 10; time: System.GreenwichMeanTime; LTPs: System.LocalTimeParameters; timeFromServer: BOOLEAN ¬ TRUE; getTimeString: LONG STRING ¬ NIL; teMP: CARDINAL = ProcessorFace.mp; ProcessorFace.SetMP[PilotMP.cTimeNotAvailable+3000]; [time, LTPs] ¬ OthelloOps.GetTimeFromTimeServer[ ! OthelloOps.TimeServerError => IF error=noResponse THEN { IF (timeTrys ¬ timeTrys-1)=0 THEN {timeFromServer ¬ FALSE; CONTINUE} ELSE {IF timeTrys=2 THEN OthelloDefs.WriteString["Locating Time Server..."L]; RETRY}} ELSE IF error=noCommunicationFacilities THEN { OthelloDefs.WriteLine["not Communication Facilities to find time"L]; timeFromServer ¬ FALSE; CONTINUE} ELSE ERROR]; ProcessorFace.SetMP[teMP]; IF timeFromServer THEN BEGIN IF timeTrys # 10 THEN OthelloDefs.WriteLine["success"L]; System.SetLocalTimeParameters[LTPs]; OthelloOps.SetProcessorTime[time]; startTime ¬ time; RETURN; END; OthelloDefs.WriteLine["failed.\rPlease enter time information (type ? for help)"L]; getTimeString ¬ z.NEW[StringBody[10]]; LTPs ¬ GetTimeZoneFromUser[@getTimeString ! TryAgain => RETRY]; System.SetLocalTimeParameters[LTPs]; spacesInStringOK ¬ TRUE; GetTimeFromUser[@getTimeString ! TryAgain => RETRY]; spacesInStringOK ¬ FALSE; z.FREE[@getTimeString]; ProcessorFace.SetMP[teMP]; END; GetTimeFromUser: PROCEDURE [p: POINTER TO LONG STRING] = { timePrompt: STRING = "Please Enter the date and 24 hour time in form DD-MMM-YY HH:MM:SS Time: "L; IF OthelloOps.IsTimeValid[] THEN BEGIN OthelloDefs.WriteString["Current time"L]; WriteTime[System.GetGreenwichMeanTime[]]; OthelloDefs.NewLine[]; IF ~Yes["Do you wish to change the time?: "L] THEN RETURN; END; IF p#NIL THEN p.length ¬ 0; DO time: System.GreenwichMeanTime; GetName[timePrompt, p]; time ¬ PackedTimeFromString[p­, FALSE]; IF time=System.gmtEpoch THEN { OthelloDefs.WriteLine["Invalid date/time -- please try again."L]; LOOP}; OthelloDefs.WriteString["Set time to"L]; WriteTime[time, TRUE]; OthelloDefs.NewLine[]; IF Yes["Okay?: "L] THEN BEGIN OthelloOps.SetProcessorTime[time]; startTime ¬ time; EXIT; END; ENDLOOP}; GetTimeZoneFromUser: PROCEDURE [string: POINTER TO LONG STRING] RETURNS [ltp: System.LocalTimeParameters] = { GetNum: PROCEDURE [ prompt: STRING, min, max, default: INTEGER] RETURNS [ans: INTEGER] = { string.length ¬ 0; String.AppendDecimal[string­, default]; DO isNeg: BOOLEAN ¬ FALSE; OthelloDefs.WriteString[prompt]; OthelloDefs.WriteChar['[]; IF ans < 0 THEN OthelloDefs.WriteChar['-]; OthelloDefs.WriteLongNumber[ABS[min]]; OthelloDefs.WriteString[".."L]; OthelloDefs.WriteLongNumber[max]; OthelloDefs.WriteString["]: "L]; GetName[dest: string, signalQuestion: TRUE]; ans ¬ 0; FOR i: CARDINAL IN [0..string.length) DO IF i=0 AND string[i]='- THEN {isNeg ¬ TRUE; LOOP}; IF string[i] NOT IN ['0..'9] THEN EXIT; ans ¬ 10*ans + string[i] - '0; REPEAT FINISHED => { IF isNeg THEN ans ¬ -ans; IF ans IN [min..max] THEN RETURN}; ENDLOOP; OthelloDefs.WriteLine["Bad Number !"L]; ENDLOOP}; dstSpiel: STRING = " The ""First day of DST"" is the day of the year on or before which Daylight Savings Time takes effect, where: 1 => January 1 366 => December 31. (The correspondence between numbers and days is based on a leap year. Similarly, ""Last day of DST"" is the day of the year on or before which Daylight Savings Time ends. Note that in any given year, Daylight Savings Time actually begins and ends at 2 AM on the last Sunday not following the specified date. The system makes this adjustment for you automatically. The normal values are 121 (April 30) for the first day of DST 305 (October 31) for the last day of DST. If Daylight Savings Time is not observed locally, both values should be set to zero."L; ZoneSpiel: STRING = " Number of hours between Greenwich and local time. For time zones west of Greenwich, the offset is negative; for time zones east of Greenwich, the offset is positive. Examples: San Francisco -8 hours (Pacific time zone) Denver -7 hours (Mountain time zone) Chicago -6 hours (Central time zone) Boston -5 hours (Eastern time zone)"L; n: INTEGER; n ¬ GetNum[prompt: "Time zone offset from Greenwich "L, min: -12, max: 12, default: -8 ! Question => {OthelloDefs.WriteLine[ZoneSpiel]; RETRY}]; ltp.direction ¬ IF n<0 THEN west ELSE east; ltp.zone ¬ ABS[n]; ltp.zoneMinutes ¬ GetNum[prompt: "Minute offset "L, min: 0, max: 59, default: 0 ! Question => {OthelloDefs.WriteLine["\rAlmost always zero"L]; RETRY}]; ltp.beginDST ¬ GetNum[prompt: "First day of DST "L, min: 0, max: 366, default: 121 ! Question => {OthelloDefs.WriteLine[dstSpiel]; RETRY}]; ltp.endDST ¬ GetNum[prompt: "Last day of DST "L, min: 0, max: 366, default: 305 ! Question => {OthelloDefs.WriteLine[dstSpiel]; RETRY}]}; PrintHerald: PROCEDURE = BEGIN herald: STRING = [100]; String.AppendString[herald, "Oscar "L]; Version.Append[herald]; String.AppendString[herald, " of"L]; OthelloDefs.WriteString[herald]; WriteTime[Runtime.GetBuildTime[], FALSE]; OthelloDefs.NewLine[]; END; PrintBootFileDate: PROCEDURE = BEGIN when: System.GreenwichMeanTime ¬ LOOPHOLE[SDDefs.SD[SDDefs.sSystemDate]]; OthelloDefs.WriteString["This Boot File was built on"L]; WriteTime[when, FALSE]; OthelloDefs.WriteString["."L]; OthelloDefs.NewLine[]; END; PrintGermDate: PROCEDURE = BEGIN germsSD: LONG POINTER TO ARRAY [0..0) OF LONG UNSPECIFIED = LOOPHOLE[Environment.Long[any[low: SDDefs.SD, high: Boot.mdsiGerm]]]; when: System.GreenwichMeanTime ¬ LOOPHOLE[germsSD[SDDefs.sSystemDate]]; OthelloDefs.WriteString["This Germ was built on"L]; WriteTime[when, FALSE]; OthelloDefs.WriteString["."L]; OthelloDefs.NewLine[]; END; PrintMicrocodeInfo: PROCEDURE = BEGIN temp: STRING = [40]; version: MicrocodeVersion.VersionResult ¬ MicrocodeVersion.VERSION[]; when: System.GreenwichMeanTime ¬ -- 0 => Jan 1, 1901 System.AdjustGreenwichMeanTime[[0], version.releaseDate*86400]; unpacked: Time.Unpacked; OthelloDefs.WriteString["This microcode was built on "L]; unpacked ¬ Time.Unpack[when, [useThese[[west, 0, 0, 366, 366]]]]; Time.Append[temp, unpacked, FALSE]; temp.length ¬ temp.length - 9; -- Discard time = " xx:xx:xx" OthelloDefs.WriteString[temp]; OthelloDefs.WriteString["."L]; OthelloDefs.NewLine[]; OthelloDefs.WriteString["This machine is a "L]; OthelloDefs.WriteString[ SELECT version.machineType FROM dolphin => "Dolphin"L, dorado => "Dorado"L, dandelion => "Dandelion"L, dicentra => "Dicentra"L, ENDCASE => "??"L]; OthelloDefs.WriteString[". FloatintPoint = "L]; OthelloDefs.WriteString[IF version.floatingPoint THEN "TRUE"L ELSE "FALSE"L]; OthelloDefs.WriteString[", Cedar = "L]; OthelloDefs.WriteString[IF version.cedar THEN "TRUE"L ELSE "FALSE"L]; OthelloDefs.WriteString["."L]; OthelloDefs.NewLine[]; END; maxFreePages: LONG CARDINAL ¬ InitMaxFreePages[]; mStoreImplInOscar: CARDINAL = 1FE8H; InitMaxFreePages: PROCEDURE RETURNS [LONG CARDINAL] = { mStoreImpl: POINTER TO FRAME [MStoreImpl] = LOOPHOLE[mStoreImplInOscar]; RETURN[mStoreImpl.countFree]; }; PrintMemorySize: PROCEDURE = BEGIN total: LONG CARDINAL ¬ SpecialSpace.realMemorySize + 16*pagesPerK; pagesPerK: CARDINAL = 4; pagesPerBank: CARDINAL = 256; mStoreImpl: POINTER TO FRAME [MStoreImpl] = LOOPHOLE[mStoreImplInOscar]; temp: STRING = [200]; String.AppendString[temp, "There are "L]; String.AppendLongDecimal[temp, SpecialSpace.realMemorySize]; String.AppendString[temp, " pages of real memory. (With a 16K map, that's "L]; String.AppendLongDecimal[temp, Environment.bytesPerWord*total/pagesPerK]; String.AppendString[temp, "K Bytes.)"L]; String.AppendChar[temp, Ascii.CR]; IF total MOD pagesPerBank # 0 THEN BEGIN String.AppendString[temp, "It looks like some pages have been lost."L]; String.AppendChar[temp, Ascii.CR]; END; maxFreePages ¬ MAX[maxFreePages, mStoreImpl.countFree]; String.AppendString[temp, "There are "L]; String.AppendLongDecimal[temp, mStoreImpl.countFree]; String.AppendString[temp, " pages of free memory."L]; IF maxFreePages # mStoreImpl.countFree THEN BEGIN String.AppendString[temp, " (Once there were "L]; String.AppendLongDecimal[temp, maxFreePages]; String.AppendString[temp, ".)"L]; END; OthelloDefs.WriteLine[temp]; END; PrintPIDs: PROCEDURE = BEGIN me: System.HostNumber = System.localHostNumber; Push: Format.StringProc = BEGIN OthelloDefs.WriteString[s]; END; OthelloDefs.WriteString["Processor = "L]; Format.HostNumber[Push, me, hex]; OthelloDefs.WriteString[" = "L]; Format.HostNumber[Push, me, octal]; OthelloDefs.WriteString[" = "L]; Format.HostNumber[Push, me, productSoftware]; OthelloDefs.WriteLine["."L]; END; GetBootInfo: PUBLIC PROCEDURE[type: OthelloOps.BootFileType, info: LONG STRING] RETURNS[exists: BOOLEAN] = BEGIN info.length ¬ 0; SELECT type FROM hardMicrocode => BEGIN version: MicrocodeVersion.VersionResult ¬ MicrocodeVersion.VERSION[]; when: System.GreenwichMeanTime ¬ -- 0 => Jan 1, 1901 System.AdjustGreenwichMeanTime[[0], version.releaseDate*86400]; unpacked: Time.Unpacked; unpacked ¬ Time.Unpack[when, [useThese[[west, 0, 0, 366, 366]]]]; Time.Append[info, unpacked, FALSE]; info.length ¬ info.length - 9; -- Discard time = " xx:xx:xx" String.AppendString[info, SELECT version.machineType FROM dolphin => ", Dolphin"L, dorado => ", Dorado"L, dandelion => ", Dandelion"L, dicentra => ", Dicentra"L, ENDCASE => "??"L]; String.AppendString[info, ", Float = "L]; String.AppendString[info, IF version.floatingPoint THEN "T"L ELSE "F"L]; String.AppendString[info, ", Cedar = "L]; String.AppendString[info, IF version.cedar THEN "T"L ELSE "F"L]; END; softMicrocode => String.AppendString[info, "None"L]; germ => BEGIN germsSD: LONG POINTER TO ARRAY [0..0) OF LONG UNSPECIFIED = LOOPHOLE[Environment.Long[any[low: SDDefs.SD, high: Boot.mdsiGerm]]]; when: System.GreenwichMeanTime ¬ LOOPHOLE[germsSD[SDDefs.sSystemDate]]; Time.Append[info, Time.Unpack[when]]; END; pilot => BEGIN when: System.GreenwichMeanTime ¬ LOOPHOLE[SDDefs.SD[SDDefs.sSystemDate]]; Time.Append[info, Time.Unpack[when]]; END; ENDCASE => String.AppendString[info, "ENDCASE"L]; END; Process.Detach[FORK Commander[]]; END..