-- 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.