-- VolumeInitCommandImpl, last edited by -- Johnsson 12-Sep-83 22:47:20 -- Saaranzin 14-Dec-83 15:20:28 -- elliott 17-Feb-84 15:12:02 -- Conde 18-Jul-84 13:58:37 -- This file is the command Processor. DIRECTORY BitBlt USING [AlignedBBTable, BITBLT, BBptr, BBTableSpace], File USING [Error, ErrorType, Unknown], Environment USING [bitsPerWord], ESCAlpha USING [aBITBLT], Format USING [HostNumber, StringProc], Frame USING [Free, GetReturnFrame, ReadLocalWord, ReadPC, WritePC], Heap USING [systemZone], KeyStations USING [D1, D2, KeyBits], Inline USING [BITNOT, HighHalf, LowHalf], OthelloDefs, OthelloOps USING [ GetTimeFromTimeServer, IsTimeValid, SetProcessorTime, TimeServerError], PhysicalVolume USING [Error, ErrorType, NeedsScavenging], PilotClient USING [], PrincOps USING [ ControlLink, ESCTrapTable, frameSizeMap, LocalFrameHandle, LocalOverhead, OpTrapTable], Process USING [Pause, SecondsToTicks], Runtime USING [GetBuildTime, IsBound], SpecialRuntime USING [GetCurrentSignal], SpecialSpace USING [realMemorySize], SpecialSystem USING [GetProcessorID], Scavenger USING [Error, ErrorType], String USING [ AppendChar, AppendCharAndGrow, AppendDecimal, AppendLongNumber, EquivalentSubString, InvalidNumber, StringBoundsFault, StringToNumber, SubStringDescriptor, UpperCase], System USING [ GetGreenwichMeanTime, GreenwichMeanTime, gmtEpoch, LocalTimeParameters, GetLocalTimeParameters, SetLocalTimeParameters], TTY USING [ BlinkDisplay, CharsAvailable, Create, CreateTTYInstance, GetChar, Handle, nullHandle, PutChar, PutString, ResetUserAbort, UserAbort], Time USING [ Append, defaultTime, Invalid, Pack, Unpack, Unpacked, useGMT, useSystem], UserTerminal USING [ CursorArray, GetCursorPattern, keyboard, SetCursorPattern], Volume USING [ InsufficientSpace, NeedsScavenging, NotOpen, ReadOnly, Unknown], VolumeConversion USING [Error, ErrorType]; UtilityPilotClientImpl: PROGRAM IMPORTS BitBlt, File, Format, Frame, Heap, Inline, OthelloDefs, OthelloOps, PhysicalVolume, Process, Runtime, SpecialRuntime, SpecialSpace, SpecialSystem, Scavenger, String, System, Time, TTY, AdmTTY: TTY, UserTerminal, Volume, VolumeConversion EXPORTS OthelloDefs, PilotClient = BEGIN 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; 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: PROC [index: CARDINAL], index: CARDINAL] = CODE; ForAllCommandProcs: PROC [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: PROC = { WidthProc: PROC [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 => { WriteString[myNameIs]; THROUGH [myNameIs.length..tabWidth) DO WriteChar[' ] ENDLOOP; WriteLine[myHelpIs]; CONTINUE}; IndexTooLarge => EXIT]; ENDLOOP ENDLOOP; WriteLine[ "In General, Del will abort current command, ? will explain options"L]}; TimeUser: PROC [index: CARDINAL] = { SELECT index FROM 0 => { SIGNAL MyNameIs[myNameIs: "Time"L, myHelpIs: "Time of day"L]; WriteString["Current time"L]; WriteTime[Time.defaultTime, TRUE]}; 1 => Help[]; ENDCASE => ERROR IndexTooLarge}; RegisterCommandProc: PUBLIC PROC [ commandProc: POINTER TO CommandProcessor] = { commandProc.next ← commands; commands ← commandProc}; commands: POINTER TO CommandProcessor ← @helpCommandProcessor; helpCommandProcessor: CommandProcessor ← [TimeUser, NIL]; -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Basic command processing -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CollectCommand: PROC RETURNS [ p: PROC [index: CARDINAL], index: CARDINAL] = { ExplainOptions: PROC = { first: BOOLEAN ← TRUE; WriteChar['?]; IF userString.length # 0 THEN { P: PROC [s: STRING] = { IF HeadMatch[s, userString.length] THEN { WriteString[IF first THEN "\rCurrent Options Are: "L ELSE ", "L]; WriteString[s]; first ← FALSE}}; ForAllCommandProcs[P]}; IF first THEN { -- Didn't match... tell all P: PROC [s: STRING] = { IF ~first THEN WriteString[", "L]; WriteString[s]; first ← FALSE}; WriteString["\rValid Commands Are: "L]; ForAllCommandProcs[P]}; WriteString["\r> "L]; WriteString[userString]}; FindAnswer: TYPE = RECORD [ SELECT how: * FROM none => NULL, many => NULL, one => [proc: PROC [index: CARDINAL], index: CARDINAL], ENDCASE]; FindPossibles: PROC RETURNS [ans: FindAnswer ← [none[]]] = { P: PROC [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 { 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 WriteChar[userString[head]]; head ← head + 1 ENDLOOP}; HeadMatch: PROC [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: PROC [c: CHARACTER] RETURNS [CHARACTER] = { RETURN[IF c IN ['A..'Z] THEN c + ('a - 'A) ELSE c]}; userString: STRING = [100]; userString.length ← 0; WriteString["> "L]; DO c: CHARACTER = ReadChar[]; SELECT c FROM DEL => {WriteLine[" XXX"L]; ERROR TryAgain}; BS, ControlA => IF userString.length # 0 THEN EraseTTYChar[userString[userString.length ← userString.length - 1]]; ControlW => IF userString.length # 0 THEN DO 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 => { IF Runtime.IsBound[LOOPHOLE[OthelloDefs.AlternateGetCMFile]] AND userString.length > 1 AND userString[0] = '@ THEN { NewLine[]; OthelloDefs.AlternateGetCMFile[userString ! OthelloDefs.MyNameIs => RESUME]; ERROR TryAgain}; IF prometheusBound THEN AbortingCommand["Script Error"L] ELSE BlinkDisplay[]}; many => NULL; one => RETURN[theAns.proc, theAns.index]; ENDCASE => ERROR}; ENDCASE => IF (userString.length ← userString.length + 1) = userString.maxlength THEN { WriteLine[" Command too long!"L]; ERROR TryAgain} ELSE WriteChar[userString[userString.length - 1] ← c]; ENDLOOP}; -- ~~~~~~~~~~~~~~~~~~~~~~~~ -- Utility-Type Functions -- ~~~~~~~~~~~~~~~~~~~~~~~~ Confirm: PUBLIC PROC [how: OthelloDefs.ConfirmType ← once] = { IF CommandFileActive[] THEN RETURN; WriteString["Are you "L]; IF how = thrice THEN WriteString["still "L]; WriteString["sure? [y or n]: "L]; DO c: CHARACTER = ReadChar[]; SELECT c FROM 'y, 'Y, CR => {WriteLine["Yes"L]; EXIT}; 'n, 'N, DEL => {WriteLine["No"L]; ERROR TryAgain}; ENDCASE => BlinkDisplay[]; ENDLOOP; IF how = twice THEN { Process.Pause[Process.SecondsToTicks[3]]; FlushInput[]; Confirm[thrice]}}; DebugAsk: PUBLIC PROC = { WriteString["\rType ControlP to muddle on........"L]; WHILE ReadChar[] # ControlP DO ENDLOOP; NewLine[]}; spacesInStringOK: BOOLEAN ← FALSE; GetName: PUBLIC PROC [ prompt: STRING ← NIL, dest: POINTER TO LONG STRING, how: OthelloDefs.EchoNoEcho ← echo, signalQuestion: BOOLEAN ← FALSE] = BEGIN first: BOOLEAN ← TRUE; EraseChar: PROC = { IF dest.length = 0 THEN RETURN; dest.length ← dest.length - 1; EraseTTYChar[IF how = echo THEN dest[dest.length] ELSE '*]; IF dest.length = 0 AND dest.maxlength > 20 THEN { Heap.systemZone.FREE[dest]; dest↑ ← Heap.systemZone.NEW[StringBody[10]]}}; CWriteC: PROC [c: CHARACTER] = {WriteChar[IF how = echo THEN c ELSE '*]}; CWriteString: PROC = { FOR i: CARDINAL IN [0..dest.length) DO CWriteC[dest[i]] ENDLOOP}; IF dest↑ = NIL THEN dest↑ ← Heap.systemZone.NEW[StringBody[10]]; WriteString[prompt]; CWriteString[]; DO c: CHARACTER = ReadChar[]; SELECT TRUE FROM c = BS, c = ControlA => EraseChar[]; (c = SP AND ~spacesInStringOK), c = CR => {NewLine[]; RETURN}; c = DEL => {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; WriteString[prompt]; CWriteString[]; LOOP}; c >= SP => { IF first THEN WHILE dest.length#0 DO EraseChar[] ENDLOOP; String.AppendCharAndGrow[dest, c, Heap.systemZone]; CWriteC[dest[dest.length-1]]}; ENDCASE => BlinkDisplay[]; first ← FALSE; ENDLOOP; END; numberString: LONG STRING ← NIL; ReadNumber: PUBLIC PROC [ 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 ← Heap.systemZone.NEW[StringBody[15]]; numberString.length ← 0; String.AppendLongNumber[numberString, default, 10]}; WriteString[prompt]; WriteChar['[]; WriteLongNumber[min]; WriteString[".."L]; WriteLongNumber[max]; 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 { Heap.systemZone.FREE[@numberString]; RETURN}; ENDLOOP; WriteLine["Bad Number !"L]; ENDLOOP}; ReadShortNumber: PUBLIC PROC [ prompt: STRING, min, max, default: LONG CARDINAL] RETURNS [CARDINAL] = { RETURN[Inline.LowHalf[ ReadNumber[prompt, min, MIN[max, LONG[LAST[CARDINAL]]], default]]]}; WriteFixedWidthNumber: PUBLIC PROC [ x: LONG CARDINAL, count: CARDINAL, base: CARDINAL ← 10] = { WFD: PROC [x: LONG CARDINAL, c: CARDINAL] = { IF c = count THEN RETURN; WFD[x/base, c + 1]; WriteChar[IF c = 0 OR x # 0 THEN Inline.LowHalf[x MOD base] + '0 ELSE ' ]}; WFD[x, 0]}; WriteLongNumber: PUBLIC PROC [num: LONG CARDINAL] = { s: STRING ← [40]; s.length ← 0; String.AppendLongNumber[s, num, 10]; WriteString[s]}; WriteOctal: PUBLIC PROC [num: CARDINAL] = { IF num # 0 THEN WriteOctal[num/8]; WriteChar[(num MOD 8) + '0]}; Yes: PUBLIC PROC [s: STRING] RETURNS [BOOLEAN] = { WriteString[s]; DO SELECT ReadChar[] FROM 'Y, 'y, CR => {WriteLine["yes"L]; RETURN[TRUE]}; 'N, 'n, DEL => {WriteLine["no"L]; RETURN[FALSE]}; ENDCASE => WriteChar['?]; ENDLOOP}; -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Time munging -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- string format must be: bDD-MMM-YYbbHH:MM:SSbbZZTb PackedTimeFromString: PUBLIC PROC [ s: LONG STRING, justDate: BOOLEAN] RETURNS [t: System.GreenwichMeanTime] = { Empty: PROC [s: LONG STRING] RETURNS [BOOLEAN] = { RETURN[s = NIL OR s.length = 0]}; EquivalentChar: PUBLIC PROC [c1, c2: CHARACTER] RETURNS [BOOLEAN] = { RETURN[String.UpperCase[c1] = String.UpperCase[c2]]}; GetToken: PROC [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: PROC [s: LONG STRING] RETURNS [t: System.GreenwichMeanTime] = { Get: PROC RETURNS [CARDINAL] = { s1.length ← 0; nextChar ← GetToken[s1, s, nextChar]; RETURN[s1.length]}; GetNumber: PROC 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: PROC [ t: System.GreenwichMeanTime, showDay: BOOLEAN ← TRUE, type: {system, gmt, pacific} ← system] = { 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, SELECT type FROM pacific => [useThese[[west, 8, 0, 121, 305]]], gmt => Time.useGMT, ENDCASE => Time.useSystem]]; IF showDay THEN { WriteChar[' ]; WriteString[days[Time.Unpack[t].unpacked.weekday]]}; IF temps[0] # ' THEN WriteChar[' ]; WriteLine[temps]}; -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- The Big Loop -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ prometheusBound: BOOLEAN = Runtime.IsBound[LOOPHOLE[OthelloDefs.GetCannedScript]]; Run: PUBLIC PROC = BEGIN DO TellError: PROC [s: LONG STRING] = { IF prometheusBound THEN OthelloDefs.ThereIsAnError[]; commandIndex ← LAST[CARDINAL]; NewLine[]; WriteString[s]}; p: PROC [index: CARDINAL]; i: CARDINAL; IF (~CommandFileActive[]) AND prometheusBound THEN { ResetAbort[]; OthelloDefs.GetCannedScript[]}; IF CommandFileActive[] THEN CheckUserAbort[ ! ABORTED => {TellError["Command File Aborted\r"L]; LOOP}] ELSE ResetAbort[]; [p, i] ← CollectCommand[ ! TryAgain => RETRY; AbortingCommand => {TellError[reason]; WriteLine[reasonOne]; LOOP}]; NewLine[]; p[i ! MyNameIs => RESUME; ABORTED => {TellError["ABORTED\r"L]; CONTINUE}; AbortingCommand => { TellError[reason]; WriteLine[reasonOne]; CONTINUE}; File.Unknown => { TellError["File.Unknown"L]; DebugAsk[]; CONTINUE}; File.Error => { PrintNames: PROC [x: File.ErrorType] = { e: ARRAY File.ErrorType OF STRING = [ invalidParameters: "invalidParameters"L, reservedType: "reservedType"L]; WriteString[e[x]]}; TellError["File.Error["L]; PrintNames[type]; WriteChar[']]; DebugAsk[]; CONTINUE}; PhysicalVolume.Error => { PrintNames: PROC [x: PhysicalVolume.ErrorType] = { e: ARRAY PhysicalVolume.ErrorType OF STRING = [ badDisk: "badDisk"L, badSpotTableFull: "badSpotTableFull"L, containsOpenVolumes: "containsOpenVolumes"L, diskReadError: "diskReadError"L, hardwareError: "hardwareError"L, hasPilotVolume: "hasPilotVolume"L, alreadyAsserted: "alreadyAsserted"L, insufficientSpace: "insufficientSpace"L, invalidHandle: "invalidHandle"L, nameRequired: "nameRequired"L, needsConversion: "needsConversion"L, notReady: "notReady"L, noSuchDrive: "noSuchDrive"L, noSuchLogicalVolume: "noSuchLogicalVolume"L, physicalVolumeUnknown: "physicalVolumeUnknown"L, writeProtected: "writeProtected"L, wrongFormat: "wrongFormat"L]; WriteString[e[x]]}; TellError["PhysicalVolume.Error["L]; PrintNames[error]; WriteChar[']]; DebugAsk[]; CONTINUE}; PhysicalVolume.NeedsScavenging => { TellError["PhysicalVolume.NeedsScavenging"L]; DebugAsk[]; CONTINUE}; Scavenger.Error =>{ PrintNames: PROC [x: Scavenger.ErrorType] = { e: ARRAY Scavenger.ErrorType OF STRING = [ cannotWriteLog: "cannotWriteLog"L, noSuchPage: "noSuchPage"L, orphanNotFound: "orphanNotFound"L, volumeOpen: "volumeOpen"L, diskHardwareError: "diskHardwareError"L, diskNotReady: "diskNotReady"L, needsConversion: "needsConversion"L, needsRiskyRepair: "needsRiskyRepair"L]; WriteString[e[x]]}; TellError["Scavenger.Error["L]; PrintNames[error]; WriteChar[']]; DebugAsk[]; CONTINUE}; VolumeConversion.Error =>{ PrintNames: PROC [x: VolumeConversion.ErrorType] = { e: ARRAY VolumeConversion.ErrorType OF STRING = [ hardwareBroken: "hardwareBroken"L, lostLog: "lostLog"L, runPreviousScavenger: "runPreviousScavenger"L, volumeVersionTooNew: "volumeVersionTooNew"L, volumeVersionTooOld: "volumeVersionTooOld"L]; WriteString[e[x]]}; TellError["VolumeConversion.Error["L]; PrintNames[error]; WriteChar[']]; DebugAsk[]; CONTINUE}; Volume.InsufficientSpace => { TellError["Volume.InsufficientSpace"L]; DebugAsk[]; CONTINUE}; Volume.NotOpen => { TellError["Volume.NotOpen"L]; DebugAsk[]; CONTINUE}; Volume.NeedsScavenging => { TellError["Please Scavenge the volume first"L]; CONTINUE}; Volume.Unknown => { TellError["Volume.Unknown"L]; DebugAsk[]; CONTINUE}; Volume.ReadOnly => { TellError["Volume.ReadOnly"L]; DebugAsk[]; CONTINUE}; String.StringBoundsFault => { TellError["String.StringBoundsFault"L]; DebugAsk[]; CONTINUE}; TryAgain => CONTINUE; ANY => { signal: SIGNAL; args: PrincOps.LocalFrameHandle; TellError["Uncaught Signal = ["L]; [signal: signal, signalArgs: args] ← SIGNAL SpecialRuntime.GetCurrentSignal; WriteOctal[Inline.LowHalf[LOOPHOLE[signal]]]; WriteChar[',]; WriteOctal[Inline.HighHalf[LOOPHOLE[signal]]]; WriteChar[']]; IF args # NIL THEN { size: CARDINAL ← PrincOps.frameSizeMap[Frame.ReadLocalWord[args].fsi] - SIZE[PrincOps.LocalOverhead]; WriteString[", msg = ["L]; FOR i: CARDINAL IN [0..size-1) DO WriteOctal[args[i]]; WriteString[", "L] ENDLOOP; WriteOctal[args[size-1]]; WriteChar[']]; Frame.Free[args]}; DebugAsk[]; CONTINUE}]; ENDLOOP; END; -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- TTY Interface Stuff -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- These two BitBlt procedures adapted from ProcessorHeadDLion HasBitBlt: PROC RETURNS [hasBitBlt: BOOLEAN ← FALSE] = { -- Execute a dummy BitBlt to find out if the microcode implements it. dummySrc: BOOLEAN ← TRUE; bba: BitBlt.BBTableSpace; bbt: BitBlt.BBptr = BitBlt.AlignedBBTable[@bba]; escTrap: PrincOps.OpTrapTable ← PrincOps.ESCTrapTable; oldTrapValue: PrincOps.ControlLink = escTrap[ESCAlpha.aBITBLT]; bbt↑ ← [ dst: [word: @hasBitBlt, bit: 0], dstBpl: Environment.bitsPerWord, src: [word: @dummySrc, bit: 0], srcDesc: [srcBpl[Environment.bitsPerWord]], width: Environment.bitsPerWord, height: 1, flags: [ direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: null, dstFunc: null]]; escTrap[ESCAlpha.aBITBLT] ← LOOPHOLE[BITBLTUnimplemented]; BitBlt.BITBLT[bbt]; -- microcode will set hasBitBlt=TRUE; software will not. escTrap[ESCAlpha.aBITBLT] ← oldTrapValue; RETURN}; BITBLTUnimplemented: PROC [BitBlt.BBptr] = { -- If this procedure is invoked, that means that the microcode does not -- implement BitBlt (e.g. RavenMesa microcode). lf: PrincOps.LocalFrameHandle ← Frame.GetReturnFrame[]; Frame.WritePC[pc: [Frame.ReadPC[lf]+2], lf: lf]; -- increment PC past BITBLT instruction--}; UseADM: PROCEDURE RETURNS [BOOLEAN] = BEGIN -- check for ADM code loaded IF ~Runtime.IsBound[LOOPHOLE[AdmTTY.CreateTTYInstance]] THEN RETURN[FALSE]; -- check for presence of LF keyboard IF(LOOPHOLE[UserTerminal.keyboard, LONG POINTER TO KeyStations.KeyBits] [KeyStations.D1]=up OR LOOPHOLE[UserTerminal.keyboard, LONG POINTER TO KeyStations.KeyBits] [KeyStations.D2]=up) THEN RETURN[TRUE]; -- if we get here we have an LF keyboard and we have ADM code. See if BitBlt is implemented. RETURN[~HasBitBlt[]] END; useADM: BOOLEAN = UseADM[]; ttyHandle: TTY.Handle = TTYMuxCreate[]; TTYMuxCreate: PROC RETURNS [TTY.Handle] = { IF ~useADM THEN RETURN[TTY.Create["Hello"L]]; RETURN[TTY.Create[ name: "Hello"L, ttyImpl: AdmTTY.CreateTTYInstance[ "Hello"L, NIL, TTY.nullHandle].ttyImpl]]}; BlinkDisplay: PUBLIC PROC = {TTY.BlinkDisplay[ttyHandle]}; CheckUserAbort: PUBLIC PROC = { IF TTY.UserAbort[ttyHandle] THEN {ResetAbort[]; ERROR ABORTED}}; EraseTTYChar: PROC [c: CHARACTER] = { SELECT c FROM IN [' ..'~] => NULL; CR => RETURN; ENDCASE => EraseTTYChar[' ]; WriteChar[BS]; WriteChar[' ]; WriteChar[BS]}; ReadChar: PUBLIC PROC RETURNS [c: CHARACTER] = { gotIt: BOOLEAN; [gotIt, c] ← GetCommandFileCharacter[]; IF gotIt THEN RETURN; RETURN[TTY.GetChar[ttyHandle]]}; SetCursor: PUBLIC PROC [c: OthelloDefs.Cursor] = { cursor: ARRAY OthelloDefs.Cursor OF UserTerminal.CursorArray = [ pointer: [ 100000B, 140000B, 160000B, 170000B, 174000B, 176000B, 177000B, 170000B, 154000B, 114000B, 006000B, 006000B, 003000B, 003000B, 001400B, 001400B], ftp: [ 000177B, 076077B, 040037B, 040017B, 070007B, 043703B, 040401B, 040400B, 000400B, 100436B, 140421B, 160421B, 170036B, 174020B, 176020B, 177020B]]; IF ~useADM THEN UserTerminal.SetCursorPattern[cursor[c]]; cursorFlipped ← FALSE}; cursorFlipped: BOOLEAN; FlipCursor: PUBLIC PROC = { IF ~useADM THEN { c: UserTerminal.CursorArray ← UserTerminal.GetCursorPattern[]; FOR i: CARDINAL IN [0..LENGTH[c]) DO c[i] ← Inline.BITNOT[c[i]] ENDLOOP; UserTerminal.SetCursorPattern[c]} ELSE { IF cursorFlipped THEN WriteChar[BS] ELSE WriteChar[SP]; cursorFlipped ← ~cursorFlipped}}; FlushInput: PROC = { UNTIL TTY.CharsAvailable[ttyHandle] = 0 DO [] ← TTY.GetChar[ttyHandle] ENDLOOP}; NewLine: PUBLIC PROC = {WriteChar[CR]}; ResetAbort: PROC = {TTY.ResetUserAbort[ttyHandle]}; WriteChar: PUBLIC PROC [c: CHARACTER] = { IF prometheusBound AND OthelloDefs.SuppressOutput[] THEN RETURN; TTY.PutChar[ttyHandle, c]}; WriteLine: PUBLIC PROC [s: LONG STRING] = {WriteString[s]; NewLine[]}; WriteString: PUBLIC PROC [s: LONG STRING] = { IF prometheusBound AND OthelloDefs.SuppressOutput[] THEN RETURN; IF s # NIL THEN TTY.PutString[ttyHandle, s]}; command: LONG STRING ← NIL; commandIndex: CARDINAL ← 0; CommandFileActive: PROC RETURNS [BOOLEAN] = INLINE {RETURN[command#NIL]}; GetCommandFileCharacter: PROC RETURNS [ isThere: BOOLEAN, c: CHARACTER] = INLINE { IF command # NIL THEN { IF commandIndex >= command.length THEN { Heap.systemZone.FREE[@command]; command ← NIL} ELSE { commandIndex ← commandIndex + 1; RETURN[TRUE, command[commandIndex-1]]}}; RETURN[FALSE, 0C]}; SetCommandString: PUBLIC PROC [s: LONG STRING] = { IF command # NIL THEN Heap.systemZone.FREE[@command]; command ← s; commandIndex ← 0}; -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Initialization Stuff -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GetTime: PROC = { timeTrys: CARDINAL ← 3; time: System.GreenwichMeanTime; LTPs: System.LocalTimeParameters; timeFromServer: BOOLEAN ← TRUE; getTimeString: LONG STRING ← NIL; [time, LTPs] ← OthelloOps.GetTimeFromTimeServer[ ! OthelloOps.TimeServerError => IF error=noResponse THEN { IF (timeTrys ← timeTrys-1)=0 THEN {timeFromServer ← FALSE; CONTINUE} ELSE {IF timeTrys=2 THEN WriteString["Locating Time Server..."L]; RETRY}} ELSE IF error=noCommunicationFacilities THEN { WriteLine["not Communication Facilities to find time"L]; timeFromServer ← FALSE; CONTINUE} ELSE ERROR]; IF timeFromServer THEN { IF timeTrys#3 THEN WriteLine["success"L]; System.SetLocalTimeParameters[LTPs]; OthelloOps.SetProcessorTime[time]; RETURN}; WriteLine["failed.\rPlease enter time information (type ? for help)"L]; getTimeString ← Heap.systemZone.NEW[StringBody[10]]; LTPs ← GetTimeZoneFromUser[@getTimeString ! TryAgain => RETRY]; System.SetLocalTimeParameters[LTPs]; spacesInStringOK ← TRUE; GetTimeFromUser[@getTimeString ! TryAgain => RETRY]; spacesInStringOK ← FALSE; Heap.systemZone.FREE[@getTimeString]}; GetTimeFromUser: PROC [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 { WriteString["Current time"L]; WriteTime[System.GetGreenwichMeanTime[]]; IF ~Yes["Do you wish to change the time?: "L] THEN RETURN}; IF p#NIL THEN p.length ← 0; DO time: System.GreenwichMeanTime; GetName[timePrompt, p]; time ← PackedTimeFromString[p↑, FALSE]; IF time=System.gmtEpoch THEN { WriteLine["Invalid date/time -- please try again."L]; LOOP}; WriteString["Set time to"L]; WriteTime[time]; IF Yes["Okay?: "L] THEN { OthelloOps.SetProcessorTime[time]; EXIT} ELSE LOOP ENDLOOP}; GetTimeZoneFromUser: PROC [string: POINTER TO LONG STRING] RETURNS [ltp: System.LocalTimeParameters] = { GetNum: PROC [ prompt: STRING, min, max, default: INTEGER] RETURNS [ans: INTEGER] = { string.length ← 0; String.AppendDecimal[string↑, default]; DO isNeg: BOOLEAN ← FALSE; WriteString[prompt]; WriteChar['[]; IF ans<0 THEN WriteChar['-]; WriteLongNumber[ABS[min]]; WriteString[".."L]; WriteLongNumber[max]; 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; 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 => {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 => {WriteLine["\rAlmost always zero"L]; RETRY}]; ltp.beginDST ← GetNum[prompt: "First day of DST "L, min: 0, max: 366, default: 121 ! Question => {WriteLine[dstSpiel]; RETRY}]; ltp.endDST ← GetNum[prompt: "Last day of DST "L, min: 0, max: 366, default: 305 ! Question => {WriteLine[dstSpiel]; RETRY}]}; PrintHerald: PROC = { string: STRING = "Hello 11.0 of "L; IF useADM THEN WriteChar['\032]; -- clear screen WriteString[ "Copyright (C) Xerox Corporation 1983, 1984. All rights reserved.\n\n"L]; WriteString[string]; WriteTime[Runtime.GetBuildTime[], FALSE, pacific]}; PrintPIDs: PROC = { w: Format.StringProc = {WriteString[s]}; WriteString["Processor = "L]; Format.HostNumber[proc: w, hostNumber: LOOPHOLE[SpecialSystem.GetProcessorID[]], format: hex]; WriteString[" = "L]; Format.HostNumber[proc: w, hostNumber: LOOPHOLE[SpecialSystem.GetProcessorID[]], format: octal]; WriteString["B = "L]; Format.HostNumber[proc: w, hostNumber: LOOPHOLE[SpecialSystem.GetProcessorID[]], format: productSoftware]; NewLine[]; }; PrintMemorySize: PROC = { size: LONG CARDINAL ← ((SpecialSpace.realMemorySize+255)/256)*64; WriteString["Memory size = "L]; WriteLongNumber[size*2]; WriteString["K bytes"L]; NewLine[]; }; ResetAbort[]; SetCursor[pointer]; PrintHerald[]; PrintPIDs[]; PrintMemorySize[]; GetTime[]; END.. LOG Time: 1-Oct-81 18:44:29 By: Forrest Action: Re-do module, add Time Stuff & Proc ID Time: 13-Nov-81 16:27:44 By: Forrest Action: 8.0e build Time: 19-Nov-81 9:26:07 By: Forrest Make PackedTimeFromString public for implementing SetBootFileExpirationDate Time: 17-Dec-81 17:52:16 By: Fay Action: 8.0f build -- changed herald. Time: 29-Dec-81 14:29:14 By: Fay Action: 8.0g build -- changed herald. Time: 29-Dec-81 14:29:14 By: Forrest Action: 8.0h build -- changed herald. Time: 1-Feb-82 16:11:37 By: Fay Action: 8.0i build -- changed herald. Time: 3-Feb-82 15:02:19 By: Jose Action: Print processor ID all 3 ways using Format. Time: 8-Feb-82 17:20:50 By: Fay Action: 8.0j build -- changed herald. Time: 1-Mar-82 13:55:31 By: Jose Action: final 8.0 build -- changed herald. Time: 20-Aug-82 16:49:26 By: Fasnacht Action: Change to 9.0b. Time: 16-Sep-82 11:47:54 By: Fasnacht Action: Change to 9.0c. Time: 24-Sep-82 17:24:53 By: Fasnacht Action: Change to 9.0d. Time: 30-Sep-82 13:48:48 By: Fasnacht Action: Change to 9.0. Time: 12-Dec-82 12:50:23 By: Johnsson Action: 10.0c; remove Storage.