-- DiagnosticsImplA.mesa  -  edited by:
-- Poskanzer	 9-May-83 21:57:46
-- JFung.pasa	 17-Nov-83 14:07:43  stopped bouncing
-- JFung.pasa	 24-Feb-84 16:44:13  accept typein mode
	-- domain name xsis north caused address fault (915)

DIRECTORY
  Ascii USING [CR, SP],
  Authenticator USING [firstVerifier, nullCredentials],
  ByeOps USING [ResumeBouncing, StopBouncing],
  CH USING [Element, Enumerate, NamePattern, wildCard, zeroMaxLengthNames],
  CHLookup USING [
    Error, FileserverPt, LookupFileserver, LookupMailserver, LookupPrintserver],
  CHPIDs USING [ch3fileserver, ch3mailserver, ch3printserver],
  CHStubInternal USING [FindDomainAddr],
  DiagnosticsOps USING [
    EchoUserTest, FloppyCleanReadWriteHeads, FloppyCommandFileTest,
    FloppyDisplayErrorLog, FloppyExerciser, FloppyFormatDiskette,
    FloppyStandardTest, Help, KeyboardAndMouseTest, LFDisplayTest, PutMessage,
    Tests],
  ExtendedString USING [AppendNumber],
  Format USING [HostNumber, NetworkNumber, StringProc],
  FormSW USING [
    AllocateItemDescriptor, BooleanItem, ClientItemsProcType, CommandItem,
    Destroy, Display, DisplayItem, Enumerated, EnumeratedItem,
    EnumeratedNotifyProcType, FindItem, ItemHandle, newLine, nullIndex,
    NumberItem, ProcType, StringItem],
  Heap USING [systemZone],
  NetworkStream USING [AssignNetworkAddress],
  NSString USING [AppendToMesaString, StringFromMesaString],
  OnlineDiagnostics USING [
    ErrorHandling, FloppyWhatToDoNext, GetConfirmationProc, GetFloppyChoiceProc,
    GetYesOrNoProc, SectorLength, YesOrNo],
  Process USING [Detach],
  Profile USING [GetDefaultDomain, GetDefaultOrganization, String],
  Put USING [Char, CR, Line, Text],
  String USING [
    AppendChar, AppendCharAndGrow, AppendLongNumber, AppendNumber, AppendString,
    AppendStringAndGrow, Copy, CopyToNewString],
  System USING [NetworkAddress],
  Tool USING [Create, MakeFileSW, MakeFormSW, MakeSWsProc, UnusedLogName],
  ToolWindow USING [Activate, Deactivate, TransitionProcType],
  UserInput USING [CreatePeriodicNotify, PeriodicProcType, UserAbort],
  UserTerminal USING [BlinkDisplay],
  Window USING [GetChild, GetParent, Handle, rootWindow, Stack, ValidateTree],
  WindowFont USING [FontHeight];

DiagnosticsImplA: MONITOR
  IMPORTS
    ByeOps, CH, CHLookup, CHStubInternal, DiagnosticsOps, ExtendedString, Format,
    FormSW, Heap, NetworkStream, NSString, Process, Profile, Put, String, Tool,
    ToolWindow, UserInput, UserTerminal, Window, WindowFont
  EXPORTS DiagnosticsOps =
  BEGIN

  -- TYPEs

  ConfirmIndex: TYPE = {confirm, yes, no, continue, loop, display, exit};
  FormIndex: TYPE = {
    help, start, cancel, addCommand, deleteCommand, test, floppyTest,
    currOrganization, currDomain, thisEthernetID, thisProcessorID, listFS,
    listPS, listMS, testEthernetID, testProcessorID, doubleDensity, doubleSided,
    sectorsPerTrack, sectorLength, errorHandling, operation, cmdFile,
    trackNumber, startingSector, sectorCount, increment, dataWord, loopCount,
    dataDisplayed};
  StringIndex: TYPE = {
    currOrganization, currDomain, thisEthernetID, thisProcessorID, listFS,
    listPS, listMS, testEthernetID, testProcessorID, cmdFile};

  DataHandle: TYPE = LONG POINTER TO Data;
  Data: TYPE = MACHINE DEPENDENT RECORD [
    -- File subwindow stuff
    fileSW(0): Window.Handle ← NIL,
    -- Form subwindow stuff
    -- Note: enumerateds and booleans must be word boundary
    -- aligned as addresses for them must be generated
    confirmSW(2): Window.Handle ← NIL,
    latestConfirm(4): ConfirmIndex ← confirm,
    formSW(5): Window.Handle ← NIL,
    test(7): DiagnosticsOps.Tests ← none,
    floppyTest(8): FloppyTest ← clean,
    doubleDensity(9): BOOLEAN ← TRUE,
    doubleSided(10): BOOLEAN ← FALSE,
    sectorsPerTrack(11): CARDINAL [8..26] ← 15,
    sectorLength(12): OnlineDiagnostics.SectorLength ← five12,
    errorHandling(13): OnlineDiagnostics.ErrorHandling ← stopOnError,
    operation(14): Operation ← initialize,
    trackNumber(15): CARDINAL ← 1,
    startingSector(16): CARDINAL ← 1,
    sectorCount(17): CARDINAL ← 1,
    increment(18): INTEGER ← 0,
    dataWord(19): CARDINAL ← 177777B,
    loopCount(20): CARDINAL ← 65535,
    dataDisplayed(21): DataDisplayed ← status,
    confirming(22): BOOLEAN ← FALSE,  -- mode switch - only one formSW active at a time
    reDisplay(23): BOOLEAN ← FALSE,  -- used by the enumerated notify procs
    inALoop(24): BOOLEAN ← FALSE,  -- for the floppy command file test
    cmdCount(25): [0..cmdMax] ← 0,
    cmdIndexes(26): ARRAY [0..cmdMax] OF CARDINAL ← ALL[0],  -- note unusual indexing
    strings(127): ARRAY StringIndex OF LONG STRING ← ALL[NIL]];


  FloppyTest: TYPE = {clean, standard, summary, format, exercise, cmdFile};
  Operation: TYPE = {
    initialize, recalibrate, readStatus, readHeader, readSectors, writeSectors,
    writeDeletedSectors, verify, loop, displayData, clearLog, log};
  DataDisplayed: TYPE = {status, header, sector, summary};

  -- Variable declarations.

  wh: Window.Handle ← NIL;  -- Tool's window
  toolData: DataHandle ← NIL;  -- Tool's data
  z: UNCOUNTED ZONE = Heap.systemZone;
  -- Some of the following should probably be in toolData.
  confirmation: CONDITION;  -- to let the GetXXXProc's know when ConfirmCommand has been bugged
  cmdMax: CARDINAL = 100;
  running: PUBLIC BOOLEAN ← FALSE;  -- whether there is a detached process running
  calledByBye: PUBLIC BOOLEAN ← FALSE;  -- whether we were activated by Bye
  active: BOOLEAN ← FALSE;  -- whether the tool is currently active

  -- Routines to allow the diagnostics to talk to the window.

  PutChar: PUBLIC PROCEDURE [ch: CHARACTER, minWidth: CARDINAL ← 0] =
    BEGIN
    Put.Char[toolData.fileSW, ch];
    THROUGH [1..minWidth) DO Put.Char[toolData.fileSW, Ascii.SP]; ENDLOOP;
    END;

  PutCR: PUBLIC PROCEDURE = BEGIN Put.CR[toolData.fileSW]; END;

  PutText: PUBLIC PROCEDURE [text: LONG STRING, minWidth: CARDINAL ← 0] =
    BEGIN
    Put.Text[toolData.fileSW, text];
    THROUGH [text.length..minWidth) DO
      Put.Char[toolData.fileSW, Ascii.SP]; ENDLOOP;
    END;

  PutLine: PUBLIC PROCEDURE [text: LONG STRING] =
    BEGIN Put.Line[toolData.fileSW, text]; END;

  PutNumber: PUBLIC PROCEDURE [
    number: UNSPECIFIED, radix: CARDINAL, minWidth: CARDINAL ← 0] =
    BEGIN
    text: STRING = [40];
    String.AppendNumber[text, number, radix];
    THROUGH [text.length..minWidth) DO PutChar[Ascii.SP]; ENDLOOP;
    PutText[text];
    END;

  PutLongNumber: PUBLIC PROCEDURE [
    number: LONG UNSPECIFIED, radix: CARDINAL, minWidth: CARDINAL ← 0] =
    BEGIN
    text: STRING = [40];
    String.AppendLongNumber[text, number, radix];
    THROUGH [text.length..minWidth) DO PutChar[Ascii.SP]; ENDLOOP;
    PutText[text];
    END;

  PutTextCentered: PUBLIC PROCEDURE [text: LONG STRING, width: CARDINAL ← 0] =
    BEGIN
    leftBlanks: CARDINAL = (width - text.length)/2;
    rightBlanks: CARDINAL = width - text.length - leftBlanks;
    THROUGH [0..leftBlanks) DO PutChar[Ascii.SP]; ENDLOOP;
    PutText[text];
    THROUGH [0..rightBlanks) DO PutChar[Ascii.SP]; ENDLOOP;
    END;


  GetConfirmation: PUBLIC ENTRY OnlineDiagnostics.GetConfirmationProc =
    BEGIN
    ENABLE UNWIND => NULL;
    MakeConfirmsVisible[confirm, confirm];
    DiagnosticsOps.PutMessage[msg];
    PutLine["Please select Confirm! when this is done."L];
    WAIT confirmation;
    MakeConfirmsInvisible[];
    END;

  GetYesOrNo: PUBLIC ENTRY OnlineDiagnostics.GetYesOrNoProc =
    BEGIN
    ENABLE UNWIND => NULL;
    MakeConfirmsVisible[yes, no];
    DiagnosticsOps.PutMessage[msg];
    PutLine["Please select either Yes! or No! as appropriate."L];
    WAIT confirmation;
    MakeConfirmsInvisible[];
    RETURN[
      SELECT toolData.latestConfirm FROM
        yes => OnlineDiagnostics.YesOrNo[yes],
        ENDCASE => OnlineDiagnostics.YesOrNo[no]];
    END;

  GetFloppyChoice: PUBLIC ENTRY OnlineDiagnostics.GetFloppyChoiceProc =
    BEGIN
    ENABLE UNWIND => NULL;
    MakeConfirmsVisible[continue, exit];
    PutLine["What do you want to do now?"L];
    WAIT confirmation;
    MakeConfirmsInvisible[];
    RETURN[
      SELECT toolData.latestConfirm FROM
        continue => OnlineDiagnostics.FloppyWhatToDoNext[continueToNextError],
        loop => OnlineDiagnostics.FloppyWhatToDoNext[loopOnThisError],
        display => OnlineDiagnostics.FloppyWhatToDoNext[displayStuff],
        ENDCASE => OnlineDiagnostics.FloppyWhatToDoNext[exit]];
    END;

  MakeConfirmsVisible: PROCEDURE [low, high: ConfirmIndex] =
    BEGIN
    toolData.confirming ← TRUE;
    FOR i: ConfirmIndex IN [low..high] DO
      FormSW.FindItem[toolData.confirmSW, ORD[ConfirmIndex[i]]].flags.invisible
        ← FALSE;
      ENDLOOP;
    FormSW.Display[toolData.confirmSW];
    END;

  MakeConfirmsInvisible: PROCEDURE =
    BEGIN
    toolData.confirming ← FALSE;
    FOR i: ConfirmIndex IN ConfirmIndex DO
      FormSW.FindItem[toolData.confirmSW, ORD[ConfirmIndex[i]]].flags.invisible
        ← TRUE;
      ENDLOOP;
    FormSW.Display[toolData.confirmSW];
    END;

  CheckForAbort: PUBLIC PROCEDURE =
    BEGIN IF UserInput.UserAbort[wh] THEN ERROR ABORTED; END;

  -- FormSW support routines.

  ConfirmCommand: ENTRY FormSW.ProcType =
    BEGIN
    ENABLE UNWIND => NULL;
    IF NOT toolData.confirming THEN UserTerminal.BlinkDisplay[]
    ELSE
      BEGIN
      toolData.latestConfirm ← LOOPHOLE[index, ConfirmIndex];
      NOTIFY confirmation;
      END;
    END;

  ActionCommand: FormSW.ProcType =
    BEGIN
    IF toolData.confirming OR running THEN UserTerminal.BlinkDisplay[]
    ELSE
      BEGIN
      SELECT LOOPHOLE[index, FormIndex] FROM
        help => DiagnosticsOps.Help[toolData.test];
        start =>
          BEGIN  --start--
          SELECT toolData.test FROM
            display =>
              BEGIN  --display--
              IF calledByBye THEN ByeOps.StopBouncing[];
              DiagnosticsOps.LFDisplayTest[];
              UglyHackToGetAroundBugInFormSW[];
              IF calledByBye THEN ByeOps.ResumeBouncing[];
              END --display-- ;
            keyboard =>
              BEGIN  --keyboard--
              IF calledByBye THEN ByeOps.StopBouncing[];
              DiagnosticsOps.KeyboardAndMouseTest[];
              UglyHackToGetAroundBugInFormSW[];
              IF calledByBye THEN ByeOps.ResumeBouncing[];
              END --keyboard-- ;
            ethernet =>
              DiagnosticsOps.EchoUserTest[
                toolData.strings[testEthernetID], toolData.strings[
                testProcessorID]];
            floppy =>
              BEGIN  --floppy--
              running ← TRUE;
              SELECT toolData.floppyTest FROM
                clean =>
                  Process.Detach[
                    FORK DiagnosticsOps.FloppyCleanReadWriteHeads[]];
                standard =>
                  Process.Detach[FORK DiagnosticsOps.FloppyStandardTest[]];
                summary =>
                  Process.Detach[FORK DiagnosticsOps.FloppyDisplayErrorLog[]];
                format =>
                  Process.Detach[FORK DiagnosticsOps.FloppyFormatDiskette[]];
                exercise =>
                  Process.Detach[FORK DiagnosticsOps.FloppyExerciser[]];
                cmdFile =>
                  BEGIN  --cmdFile--
                  IF toolData.inALoop THEN
                    BEGIN
                    CmdAppend["E,"L];
                    FormSW.DisplayItem[
                      toolData.formSW, ORD[FormIndex[cmdFile]]];
                    END;
                  Process.Detach[
                    FORK DiagnosticsOps.FloppyCommandFileTest[
                    toolData.doubleDensity, toolData.doubleSided,
                    toolData.sectorsPerTrack, toolData.sectorLength,
                    toolData.errorHandling, toolData.strings[cmdFile]]];
                  END --cmdFile-- ;
                ENDCASE;
              END --floppy-- ;
            none => NULL;
            ENDCASE;
          END --start-- ;
        cancel => [] ← ToolWindow.Deactivate[wh];
        addCommand =>
          BEGIN  --addCommand--
          temp: LONG STRING = [100];
          SELECT toolData.operation FROM
            initialize => CmdAppend["I,"L];
            recalibrate => CmdAppend["RC,"L];
            readStatus => CmdAppend["RAST,"L];
            readHeader =>
              BEGIN  --readHeader--
              String.Copy[temp, "RAH,"L];
              IF AppendTrackNumber[temp] THEN
                IF toolData.inALoop THEN
                  BEGIN IF AppendIncrement[temp] THEN CmdAppend[temp]; END
                ELSE CmdAppend[temp];
              END --readHeader-- ;
            readSectors =>
              BEGIN  --readSectors--
              String.Copy[temp, "RASE,"L];
              IF AppendTrackNumber[temp] THEN
                IF AppendStartingSector[temp] THEN
                  IF toolData.inALoop THEN
                    BEGIN IF AppendIncrement[temp] THEN CmdAppend[temp]; END
                  ELSE
                    BEGIN IF AppendSectorCount[temp] THEN CmdAppend[temp]; END;
              END --readSectors-- ;
            writeSectors, writeDeletedSectors =>
              BEGIN  --write--
              IF toolData.operation = writeSectors THEN
                String.Copy[temp, "WS,"L]
              ELSE String.Copy[temp, "WD,"L];
              IF AppendTrackNumber[temp] THEN
                IF AppendStartingSector[temp] THEN
                  IF toolData.inALoop THEN
                    BEGIN
                    IF AppendIncrement[temp] THEN
                      IF AppendDataWord[temp] THEN CmdAppend[temp];
                    END
                  ELSE
                    BEGIN
                    IF AppendSectorCount[temp] THEN
                      IF AppendDataWord[temp] THEN CmdAppend[temp];
                    END;
              END --write-- ;
            verify => CmdAppend["V,"L];
            loop =>
              BEGIN  --loop--
              IF toolData.inALoop THEN CmdAppend["E,"L]
              ELSE
                BEGIN
                String.Copy[temp, "S,"L];
                String.AppendNumber[temp, toolData.loopCount, 10];
                String.AppendString[temp, ","L];  --!! Diag2Pack.mesa uses "'", but this works.
                CmdAppend[temp];
                END;
              ToggleInALoop[];
              END --loop-- ;
            displayData =>
              CmdAppend[
                SELECT toolData.dataDisplayed FROM
                  status => "DST,"L,
                  header => "DH,"L,
                  sector => "DSE,"L,
                  summary => "DL,"L,
                  ENDCASE => "DST,"L];
            clearLog => CmdAppend["C,"L];
            log => CmdAppend["L,"L];
            ENDCASE;
          END --addCommand-- ;
        deleteCommand => CmdDelete[];
        ENDCASE => PutLine["Unknown command - should never happen!?!?"L];
      END;
    END;

  KamikazeProc: UserInput.PeriodicProcType =
    BEGIN FormSW.DisplayItem[toolData.formSW, ORD[FormIndex[start]]]; END;

  UglyHackToGetAroundBugInFormSW: PROCEDURE =
    BEGIN
    [] ← UserInput.CreatePeriodicNotify[
      proc: KamikazeProc, window: Window.rootWindow, rate: 0];
    END;

  CmdAppend: PROCEDURE [string: LONG STRING] =
    BEGIN
    IF toolData.cmdCount < cmdMax THEN
      BEGIN
      String.AppendStringAndGrow[@toolData.strings[cmdFile], string, z];
      toolData.cmdCount ← toolData.cmdCount + 1;
      toolData.cmdIndexes[toolData.cmdCount] ← toolData.strings[cmdFile].length;
      FormSW.DisplayItem[toolData.formSW, ORD[FormIndex[cmdFile]]];
      END;
    END;

  CmdDelete: PROCEDURE =
    BEGIN
    IF toolData.cmdCount > 0 THEN
      BEGIN
      ch: CHARACTER ← toolData.strings[cmdFile][
        toolData.cmdIndexes[toolData.cmdCount - 1]];
      IF ch = 'E OR ch = 'S THEN ToggleInALoop[];
      toolData.cmdCount ← toolData.cmdCount - 1;
      toolData.strings[cmdFile].length ← toolData.cmdIndexes[toolData.cmdCount];
      FormSW.DisplayItem[toolData.formSW, ORD[FormIndex[cmdFile]]];
      END;
    END;

  AppendTrackNumber: PROCEDURE [cmd: LONG STRING] RETURNS [ok: BOOLEAN] =
    BEGIN
    IF toolData.trackNumber > 76 THEN
      BEGIN
      PutLine["Track number invalid - must be between 0 and  76."L];
      ok ← FALSE;
      END
    ELSE
      BEGIN
      String.AppendNumber[cmd, toolData.trackNumber, 10];
      String.AppendString[cmd, ",0,"L];  --!! what is the 0? "keyHead", 0 or 1
      ok ← TRUE;
      END;
    END;
  AppendStartingSector: PROCEDURE [cmd: LONG STRING] RETURNS [ok: BOOLEAN] =
    BEGIN
    IF toolData.startingSector < 1
      OR toolData.startingSector > toolData.sectorsPerTrack THEN
      BEGIN
      PutLine[
        "Starting sector invalid - must be between 1 and # of sectors per track."L];
      ok ← FALSE;
      END
    ELSE
      BEGIN
      String.AppendNumber[cmd, toolData.startingSector, 10];
      String.AppendString[cmd, ","L];
      ok ← TRUE;
      END;
    END;
  AppendIncrement: PROCEDURE [cmd: LONG STRING] RETURNS [ok: BOOLEAN] =
    BEGIN
    IF toolData.increment < -2000 OR toolData.increment > 2000 THEN
      BEGIN
      PutLine["Increment invalid - must be between -2000 and 2000."L];
      ok ← FALSE;
      END
    ELSE
      BEGIN
      IF toolData.increment < 0 THEN String.AppendString[cmd, "-"L]
      ELSE String.AppendString[cmd, "+"L];
      String.AppendNumber[cmd, ABS[toolData.increment], 10];
      String.AppendString[cmd, ","L];
      ok ← TRUE;
      END;
    END;
  AppendSectorCount: PROCEDURE [cmd: LONG STRING] RETURNS [ok: BOOLEAN] =
    BEGIN
    IF toolData.sectorCount < 1
      OR toolData.sectorCount > toolData.sectorsPerTrack THEN
      BEGIN
      PutLine[
        "Sector count invalid - must be between 1 and # of sectors per track."L];
      ok ← FALSE;
      END
    ELSE
      BEGIN
      String.AppendNumber[cmd, toolData.sectorCount, 10];
      String.AppendString[cmd, ","L];
      ok ← TRUE;
      END;
    END;
  AppendDataWord: PROCEDURE [cmd: LONG STRING] RETURNS [ok: BOOLEAN] =
    BEGIN
    String.AppendNumber[cmd, toolData.dataWord, 16];
    String.AppendString[cmd, ","L];
    ok ← TRUE;
    END;

  ToggleInALoop: PROCEDURE =
    BEGIN
    toolData.inALoop ← NOT toolData.inALoop;
    IF toolData.test = floppy AND toolData.floppyTest = cmdFile THEN
      OperationNotify[
        toolData.formSW, FormSW.FindItem[
        toolData.formSW, ORD[FormIndex[operation]]], ORD[FormIndex[operation]],
        toolData.operation];
    END;

  TestNotify: FormSW.EnumeratedNotifyProcType =
    BEGIN
    SELECT LOOPHOLE[oldValue, DiagnosticsOps.Tests] FROM
      ethernet =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[currOrganization]]].flags.invisible ←
          TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[currDomain]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[thisEthernetID]]].flags.invisible ←
          TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[thisProcessorID]]].flags.invisible ←
          TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[thisProcessorID]]].flags.invisible ←
          TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[listFS]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[listPS]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[listMS]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[testEthernetID]]].flags.invisible ←
          TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[testProcessorID]]].flags.invisible ←
          TRUE;
        END;
      floppy =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[floppyTest]]].flags.invisible ← TRUE;
        END;
      none =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[start]]].flags.invisible ← FALSE;
        END;
      ENDCASE;
    SELECT toolData.test FROM
      ethernet =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[currOrganization]]].flags.invisible ←
          FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[currDomain]]].flags.invisible ← FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[thisEthernetID]]].flags.invisible ←
          FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[thisProcessorID]]].flags.invisible ←
          FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[listFS]]].flags.invisible ← FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[listPS]]].flags.invisible ← FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[listMS]]].flags.invisible ← FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[testEthernetID]]].flags.invisible ←
          FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[testProcessorID]]].flags.invisible ←
          FALSE;
        END;
      floppy =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[floppyTest]]].flags.invisible ← FALSE;
        END;
      none =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[start]]].flags.invisible ← TRUE;
        END;
      ENDCASE;
    IF LOOPHOLE[oldValue, DiagnosticsOps.Tests] = floppy
      AND toolData.floppyTest = cmdFile THEN
      BEGIN
      toolData.floppyTest ← clean;
      FloppyTestNotify[
        sw, FormSW.FindItem[sw, ORD[FormIndex[floppyTest]]], ORD[
        FormIndex[floppyTest]], FloppyTest[cmdFile]];
      END;
    IF toolData.reDisplay THEN
      BEGIN FormSW.Display[sw]; toolData.reDisplay ← FALSE; END;
    END;

  FloppyTestNotify: FormSW.EnumeratedNotifyProcType =
    BEGIN
    SELECT LOOPHOLE[oldValue, FloppyTest] FROM
      cmdFile =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[addCommand]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[deleteCommand]]].flags.invisible ←
          TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[doubleDensity]]].flags.invisible ←
          TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[doubleSided]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[sectorsPerTrack]]].flags.invisible ←
          TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[sectorLength]]].flags.invisible ←
          TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[errorHandling]]].flags.invisible ←
          TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[operation]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[cmdFile]]].flags.invisible ← TRUE;
        --SetCurrent[sw, nullIndex];
        END;
      ENDCASE;
    SELECT toolData.floppyTest FROM
      cmdFile =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[addCommand]]].flags.invisible ← FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[deleteCommand]]].flags.invisible ←
          FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[doubleDensity]]].flags.invisible ←
          FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[doubleSided]]].flags.invisible ←
          FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[sectorsPerTrack]]].flags.invisible ←
          FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[sectorLength]]].flags.invisible ←
          FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[errorHandling]]].flags.invisible ←
          FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[operation]]].flags.invisible ← FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[cmdFile]]].flags.invisible ← FALSE;
        END;
      ENDCASE;
    IF LOOPHOLE[oldValue, FloppyTest] = cmdFile THEN
      BEGIN
      oldOperation: Operation ← toolData.operation;
      toolData.operation ← initialize;
      OperationNotify[
        sw, FormSW.FindItem[sw, ORD[FormIndex[operation]]], ORD[
        FormIndex[operation]], oldOperation];
      END;
    IF toolData.reDisplay THEN
      BEGIN FormSW.Display[sw]; toolData.reDisplay ← FALSE; END;
    END;

  OperationNotify: FormSW.EnumeratedNotifyProcType =
    BEGIN
    SELECT LOOPHOLE[oldValue, Operation] FROM
      readHeader =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[trackNumber]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[increment]]].flags.invisible ← TRUE;
        --SetCurrent[sw, nullIndex];
        END;
      readSectors =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[trackNumber]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[startingSector]]].flags.invisible ←
          TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[sectorCount]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[increment]]].flags.invisible ← TRUE;
        --SetCurrent[sw, nullIndex];
        END;
      writeSectors, writeDeletedSectors =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[trackNumber]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[startingSector]]].flags.invisible ←
          TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[sectorCount]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[dataWord]]].flags.invisible ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[increment]]].flags.invisible ← TRUE;
        --SetCurrent[sw, nullIndex];
        END;
      loop =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[loopCount]]].flags.invisible ← TRUE;
        --SetCurrent[sw, nullIndex];
        END;
      displayData =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[dataDisplayed]]].flags.invisible ←
          TRUE;
        END;
      ENDCASE;
    SELECT toolData.operation FROM
      readHeader =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[trackNumber]]].flags.invisible ←
          FALSE;
        IF toolData.inALoop THEN
          FormSW.FindItem[sw, ORD[FormIndex[increment]]].flags.invisible ←
            FALSE;
        END;
      readSectors =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[trackNumber]]].flags.invisible ←
          FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[startingSector]]].flags.invisible ←
          FALSE;
        IF toolData.inALoop THEN
          FormSW.FindItem[sw, ORD[FormIndex[increment]]].flags.invisible ← FALSE
        ELSE
          FormSW.FindItem[sw, ORD[FormIndex[sectorCount]]].flags.invisible ←
            FALSE;
        END;
      writeSectors, writeDeletedSectors =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[trackNumber]]].flags.invisible ←
          FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[startingSector]]].flags.invisible ←
          FALSE;
        IF toolData.inALoop THEN
          FormSW.FindItem[sw, ORD[FormIndex[increment]]].flags.invisible ← FALSE
        ELSE
          FormSW.FindItem[sw, ORD[FormIndex[sectorCount]]].flags.invisible ←
            FALSE;
        FormSW.FindItem[sw, ORD[FormIndex[dataWord]]].flags.invisible ← FALSE;
        END;
      loop =>
        IF NOT toolData.inALoop THEN
          BEGIN
          toolData.reDisplay ← TRUE;
          FormSW.FindItem[sw, ORD[FormIndex[loopCount]]].flags.invisible ←
            FALSE;
          END;
      displayData =>
        BEGIN
        toolData.reDisplay ← TRUE;
        FormSW.FindItem[sw, ORD[FormIndex[dataDisplayed]]].flags.invisible ←
          FALSE;
        END;
      ENDCASE;
    IF toolData.reDisplay THEN
      BEGIN FormSW.Display[sw]; toolData.reDisplay ← FALSE; END;
    END;

  -- Setup and support routines.

  ClientTransition: ToolWindow.TransitionProcType =
    BEGIN
    SELECT TRUE FROM
      old = inactive =>
        BEGIN
        IF toolData = NIL THEN toolData ← z.NEW[Data ← []];
        active ← TRUE;
        END;
      new = inactive =>
        BEGIN
        IF toolData # NIL THEN
          BEGIN
          FormSW.Destroy[toolData.formSW];
          z.FREE[@toolData.strings[cmdFile]];
          z.FREE[@toolData];
          END;
        IF calledByBye THEN
          BEGIN calledByBye ← FALSE; ByeOps.ResumeBouncing[]; END;
        active ← FALSE;
        END;
      ENDCASE
    END;

  DiagnosticsActivate: PUBLIC PROCEDURE =
    BEGIN
    --calledByBye ← TRUE; 
    IF wh = NIL THEN Init[];
    ToolWindow.Activate[wh];
    Window.Stack[wh, Window.GetChild[Window.GetParent[wh]]];  -- top me
    Window.ValidateTree[];
    END;

  Init: PROCEDURE =
    BEGIN
    -- Make the tool window and its subwindows.
    wh ← Tool.Create[
      makeSWsProc: MakeSWs, initialState: inactive,
      clientTransition: ClientTransition, name: "Diagnostics"L,
      initialBox: [[512, 0], [512, 808]], tinyName1: "Diag"L,
      tinyName2: "nostics"L]
    END;

  MakeSWs: Tool.MakeSWsProc =
    BEGIN
    logName: STRING ← [40];
    Tool.UnusedLogName[unused: logName, root: "Diagnostics.log"L];
    toolData.confirmSW ← Tool.MakeFormSW[
      window: window, formProc: MakeConfirm, zone: z,
      h: 2*WindowFont.FontHeight[]];  -- should be 1
    toolData.formSW ← Tool.MakeFormSW[
      window: window, formProc: MakeForm, zone: z,
      h: 45*WindowFont.FontHeight[]];
    running ← TRUE;
    Process.Detach[FORK SetupEthernetItems[]];
    
    <<toolData.fileSW ← Tool.MakeFileSW[
      window: window, name: logName, allowTypeIn: FALSE];>>
      --changed typein mode to True.  JFung.pasa 
      --  24-Feb-84 16:44:13
    toolData.fileSW ← Tool.MakeFileSW[
      window: window, name: logName, allowTypeIn: TRUE];
  
   END;

  MakeConfirm: FormSW.ClientItemsProcType =
    BEGIN OPEN FormSW;
    -- This procedure creates the confirmation FormSW.
    formItems: LONG POINTER TO ARRAY ConfirmIndex OF FormSW.ItemHandle ← NIL;
    items ← AllocateItemDescriptor[nItems: ConfirmIndex.LAST.ORD + 1, z: z];
    formItems ← LOOPHOLE[BASE[items]];
    formItems↑ ← [
      confirm: CommandItem[
      tag: "Confirm"L, place: newLine, drawBox: TRUE, invisible: TRUE,
      proc: ConfirmCommand],
      yes: CommandItem[
      tag: "Yes"L, drawBox: TRUE, invisible: TRUE, proc: ConfirmCommand],
      no: CommandItem[
      tag: "No"L, drawBox: TRUE, invisible: TRUE, proc: ConfirmCommand],
      continue: CommandItem[
      tag: "Continue"L, drawBox: TRUE, invisible: TRUE, proc: ConfirmCommand],
      loop: CommandItem[
      tag: "Loop"L, drawBox: TRUE, invisible: TRUE, proc: ConfirmCommand],
      display: CommandItem[
      tag: "Display"L, drawBox: TRUE, invisible: TRUE, proc: ConfirmCommand],
      exit: CommandItem[
      tag: "Exit"L, drawBox: TRUE, invisible: TRUE, proc: ConfirmCommand]];
    RETURN[items: items, freeDesc: TRUE]
    END;

  MakeForm: FormSW.ClientItemsProcType =
    BEGIN OPEN FormSW;
    -- This procedure creates the main FormSW.
    formItems: LONG POINTER TO ARRAY FormIndex OF FormSW.ItemHandle ← NIL;
    EnumSeq: TYPE = RECORD [seq: SEQUENCE n: CARDINAL OF FormSW.Enumerated];
    testSeq: LONG POINTER TO EnumSeq ← z.NEW[EnumSeq [5]];
    floppyTestSeq: LONG POINTER TO EnumSeq ← z.NEW[EnumSeq [6]];
    sectorLengthSeq: LONG POINTER TO EnumSeq ← z.NEW[EnumSeq [4]];
    errorHandlingSeq: LONG POINTER TO EnumSeq ← z.NEW[EnumSeq [3]];
    operationSeq: LONG POINTER TO EnumSeq ← z.NEW[EnumSeq [12]];
    dataDisplayedSeq: LONG POINTER TO EnumSeq ← z.NEW[EnumSeq [4]];
    testSeq[0] ← ["Display"L, DiagnosticsOps.Tests[display]];
    testSeq[1] ← ["Keyboard"L, DiagnosticsOps.Tests[keyboard]];
    testSeq[2] ← ["Echo Test"L, DiagnosticsOps.Tests[ethernet]];
    testSeq[3] ← ["Floppy Disk Drive"L, DiagnosticsOps.Tests[floppy]];
    testSeq[4] ← ["None"L, DiagnosticsOps.Tests[none]];
    floppyTestSeq[0] ← ["Clean Heads"L, FloppyTest[clean]];
    floppyTestSeq[1] ← ["Standard"L, FloppyTest[standard]];
    floppyTestSeq[2] ← ["Summary"L, FloppyTest[summary]];
    floppyTestSeq[3] ← ["Format"L, FloppyTest[format]];
    floppyTestSeq[4] ← ["Exerciser"L, FloppyTest[exercise]];
    floppyTestSeq[5] ← ["Command File"L, FloppyTest[cmdFile]];
    sectorLengthSeq[0] ← ["128 bytes"L, OnlineDiagnostics.SectorLength[one28]];
    sectorLengthSeq[1] ← ["256 bytes"L, OnlineDiagnostics.SectorLength[two56]];
    sectorLengthSeq[2] ← ["512 bytes"L, OnlineDiagnostics.SectorLength[five12]];
    sectorLengthSeq[3] ← [
      "1024 bytes"L, OnlineDiagnostics.SectorLength[one024]];
    errorHandlingSeq[0] ← [
      "No Error Checking"L, OnlineDiagnostics.ErrorHandling[noChecking]];
    errorHandlingSeq[1] ← [
      "Stop on Errors"L, OnlineDiagnostics.ErrorHandling[stopOnError]];
    errorHandlingSeq[2] ← [
      "Loop on Errors"L, OnlineDiagnostics.ErrorHandling[loopOnError]];
    operationSeq[0] ← ["Initialize floppy drive"L, Operation[initialize]];
    operationSeq[1] ← ["Recalibrate"L, Operation[recalibrate]];
    operationSeq[2] ← ["Read Status"L, Operation[readStatus]];
    operationSeq[3] ← ["Read Header"L, Operation[readHeader]];
    operationSeq[4] ← ["Read Sectors"L, Operation[readSectors]];
    operationSeq[5] ← ["Write Sectors"L, Operation[writeSectors]];
    operationSeq[6] ← [
      "Write Deleted Sectors"L, Operation[writeDeletedSectors]];
    operationSeq[7] ← ["Verify"L, Operation[verify]];
    operationSeq[8] ← ["Start/Stop Loop"L, Operation[loop]];
    operationSeq[9] ← ["Display Data"L, Operation[displayData]];
    operationSeq[10] ← ["Clear Status Log"L, Operation[clearLog]];
    operationSeq[11] ← ["Log Status"L, Operation[log]];
    toolData.cmdCount ← 0;
    toolData.cmdIndexes[toolData.cmdCount] ← 0;
    toolData.inALoop ← FALSE;
    dataDisplayedSeq[0] ← ["Status"L, DataDisplayed[status]];
    dataDisplayedSeq[1] ← ["Header"L, DataDisplayed[header]];
    dataDisplayedSeq[2] ← ["Sector"L, DataDisplayed[sector]];
    dataDisplayedSeq[3] ← ["Summary Log"L, DataDisplayed[summary]];
    items ← AllocateItemDescriptor[nItems: FormIndex.LAST.ORD + 1, z: z];
    formItems ← LOOPHOLE[BASE[items]];
    formItems↑ ← [
      help: CommandItem[
      tag: "Help"L, place: newLine, drawBox: TRUE, invisible: FALSE,
      proc: ActionCommand],
      start: CommandItem[
      tag: "Start"L, drawBox: TRUE, invisible: TRUE, proc: ActionCommand],
      cancel: CommandItem[
      tag: "Cancel"L, drawBox: TRUE, invisible: FALSE, proc: ActionCommand],
      addCommand: CommandItem[
      tag: "Add Command to file"L, drawBox: TRUE, invisible: TRUE,
      proc: ActionCommand],
      deleteCommand: CommandItem[
      tag: "Delete Previous Command"L, drawBox: TRUE, invisible: TRUE,
      proc: ActionCommand],
      test: EnumeratedItem[
      tag: "Test to be executed"L, place: newLine, invisible: FALSE,
      feedback: all, value: @toolData.test, copyChoices: TRUE,
      choices: DESCRIPTOR[testSeq↑], proc: TestNotify],
      floppyTest: EnumeratedItem[
      tag: "Type of test"L, place: newLine, invisible: TRUE, feedback: all,
      value: @toolData.floppyTest, copyChoices: TRUE,
      choices: DESCRIPTOR[floppyTestSeq↑], proc: FloppyTestNotify],
      currOrganization: StringItem[
      tag: "Current Organization"L, place: newLine, invisible: TRUE,
      readOnly: TRUE, inHeap: TRUE,
      string: @toolData.strings[currOrganization]],
      currDomain: StringItem[
      tag: "Current Domain"L, place: newLine, invisible: TRUE, readOnly: TRUE,
      inHeap: TRUE, string: @toolData.strings[currDomain]],
      thisEthernetID: StringItem[
      tag: "Ethernet ID number of this machine"L, place: newLine,
      invisible: TRUE, readOnly: TRUE, inHeap: TRUE,
      string: @toolData.strings[thisEthernetID]],
      thisProcessorID: StringItem[
      tag: "Processor ID number of this machine"L, place: newLine,
      invisible: TRUE, readOnly: TRUE, inHeap: TRUE,
      string: @toolData.strings[thisProcessorID]],
      listFS: StringItem[
      tag: "FS"L, place: newLine, invisible: TRUE, readOnly: TRUE, inHeap: TRUE,
      string: @toolData.strings[listFS]],
      listPS: StringItem[
      tag: "PS"L, place: newLine, invisible: TRUE, readOnly: TRUE, inHeap: TRUE,
      string: @toolData.strings[listPS]],
      listMS: StringItem[
      tag: "MS"L, place: newLine, invisible: TRUE, readOnly: TRUE, inHeap: TRUE,
      string: @toolData.strings[listMS]],
      testEthernetID: StringItem[
      tag: "Ethernet ID number of the test partner's machine"L, place: newLine,
      invisible: TRUE, inHeap: TRUE, string: @toolData.strings[testEthernetID]],
      testProcessorID: StringItem[
      tag: "Processor ID number of the test partner's machine"L, place: newLine,
      invisible: TRUE, inHeap: TRUE,
      string: @toolData.strings[testProcessorID]],
      doubleDensity: BooleanItem[
      tag: "Double Density"L, place: newLine, invisible: TRUE,
      switch: @toolData.doubleDensity],
      doubleSided: BooleanItem[
      tag: "Double Sided"L, invisible: TRUE, switch: @toolData.doubleSided],
      sectorsPerTrack: NumberItem[
      tag: "Sectors per Track"L, invisible: TRUE,
      value: @toolData.sectorsPerTrack, notNegative: TRUE, signed: FALSE],
      sectorLength: EnumeratedItem[
      tag: "Sector Length"L, place: newLine, invisible: TRUE, feedback: all,
      value: @toolData.sectorLength, copyChoices: TRUE,
      choices: DESCRIPTOR[sectorLengthSeq↑]],
      errorHandling: EnumeratedItem[
      tag: "Error Handling"L, place: newLine, invisible: TRUE, feedback: all,
      value: @toolData.errorHandling, copyChoices: TRUE,
      choices: DESCRIPTOR[errorHandlingSeq↑]],
      operation: EnumeratedItem[
      tag: "Command File Operation"L, place: newLine, invisible: TRUE,
      feedback: one, value: @toolData.operation, copyChoices: TRUE,
      choices: DESCRIPTOR[operationSeq↑], proc: OperationNotify],
      cmdFile: StringItem[
      tag: "Commands"L, place: newLine, invisible: TRUE, readOnly: TRUE,
      inHeap: TRUE, string: @toolData.strings[cmdFile]],
      trackNumber: NumberItem[
      tag: "Track number"L, place: newLine, invisible: TRUE,
      value: @toolData.trackNumber, notNegative: TRUE, signed: FALSE],
      startingSector: NumberItem[
      tag: "Starting Sector"L, place: newLine, invisible: TRUE,
      value: @toolData.startingSector, notNegative: TRUE, signed: FALSE],
      sectorCount: NumberItem[
      tag: "Sector Count"L, place: newLine, invisible: TRUE,
      value: @toolData.sectorCount, notNegative: TRUE, signed: FALSE],
      increment: NumberItem[
      tag: "Increment (+ or -) by"L, place: newLine, invisible: TRUE,
      value: @toolData.increment, notNegative: FALSE, signed: TRUE],
      dataWord: NumberItem[
      tag: "Data Word"L, place: newLine, invisible: TRUE,
      value: @toolData.dataWord, radix: octal, notNegative: TRUE,
      signed: FALSE],
      loopCount: NumberItem[
      tag: "Loop Count"L, place: newLine, invisible: TRUE,
      value: @toolData.loopCount, notNegative: TRUE, signed: FALSE],
      dataDisplayed: EnumeratedItem[
      tag: "Data to Be Displayed"L, place: newLine, invisible: TRUE,
      feedback: all, value: @toolData.dataDisplayed, copyChoices: TRUE,
      choices: DESCRIPTOR[dataDisplayedSeq↑]]];
    z.FREE[@testSeq];
    z.FREE[@floppyTestSeq];
    z.FREE[@sectorLengthSeq];
    z.FREE[@errorHandlingSeq];
    z.FREE[@operationSeq];
    z.FREE[@dataDisplayedSeq];
    RETURN[items: items, freeDesc: TRUE]
    END;

  SetupEthernetItems: PROCEDURE =
    BEGIN  --SetupEthernetItems--
    thisNetworkAddress: System.NetworkAddress;
    -- Get the current domain and organization.
    Profile.GetDefaultOrganization[GetCurrOrganization];
    FormSW.DisplayItem[toolData.formSW, ORD[FormIndex[currOrganization]]];
    Profile.GetDefaultDomain[GetCurrDomain];
    FormSW.DisplayItem[toolData.formSW, ORD[FormIndex[currDomain]]];
    -- Get the current network and host number.
    thisNetworkAddress ← NetworkStream.AssignNetworkAddress[];
    Format.NetworkNumber[
      GetThisEthernetID, thisNetworkAddress.net, productSoftware];
    FormSW.DisplayItem[toolData.formSW, ORD[FormIndex[thisEthernetID]]];
    Format.HostNumber[
      GetThisProcessorID, thisNetworkAddress.host, productSoftware];
    FormSW.DisplayItem[toolData.formSW, ORD[FormIndex[thisProcessorID]]];
    AppendServers[];  -- List all the file servers, print servers, and mail servers.
    FormSW.DisplayItem[toolData.formSW, ORD[FormIndex[listFS]]];
    FormSW.DisplayItem[toolData.formSW, ORD[FormIndex[listPS]]];
    FormSW.DisplayItem[toolData.formSW, ORD[FormIndex[listMS]]];
    GetClearingHouse[];
    FormSW.DisplayItem[toolData.formSW, ORD[FormIndex[testEthernetID]]];
    FormSW.DisplayItem[toolData.formSW, ORD[FormIndex[testProcessorID]]];
    running ← FALSE;
    END --SetupEthernetItems-- ;

  GetCurrOrganization: PROCEDURE [s: Profile.String] =
    BEGIN
    toolData.strings[currOrganization] ← String.CopyToNewString[s, z];
    END;
  GetCurrDomain: PROCEDURE [s: Profile.String] =
    BEGIN toolData.strings[currDomain] ← String.CopyToNewString[s, z]; END;
  GetThisEthernetID: Format.StringProc =
    BEGIN toolData.strings[thisEthernetID] ← String.CopyToNewString[s, z]; END;
  GetThisProcessorID: Format.StringProc =
    BEGIN toolData.strings[thisProcessorID] ← String.CopyToNewString[s, z]; END;
  GetTestEthernetID: Format.StringProc =
    BEGIN toolData.strings[testEthernetID] ← String.CopyToNewString[s, z]; END;
  GetTestProcessorID: Format.StringProc =
    BEGIN toolData.strings[testProcessorID] ← String.CopyToNewString[s, z]; END;

  -- Append server trash, stolen from Diag1Pack.mesa

  AppendServers: PROCEDURE =
    BEGIN  --AppendServers--
    found: BOOLEAN ← FALSE;
    foundThatID: BOOLEAN ← FALSE;
    pattern: CH.NamePattern;
    index: StringIndex;
    string: LONG POINTER TO LONG STRING;
    wildString: LONG STRING ← [5];

    GetAndAppendID: PROC [name: CH.Element] =
      BEGIN  --GetAndAppendID--

      AppendID: PROC [fullName: CH.Element, info: CHLookup.FileserverPt] =
        BEGIN  --AppendID--
        temp: LONG STRING ← [100];
        -- Append the decimal representation of info.address --
        AppendDashedNumberAndGrow[string, @info.address.host, 3, 10, z];
        -- Append a blank --
        String.AppendStringAndGrow[string, " "L, z];
        -- ****************************************************************** --
        -- NOTE!!!! - The octal & hex representations of the proc IDs are not printed at this time. May be re-inserted at a future time.
        -- Append the octal representation of info.address
        -- AppendNumberAndGrow[string, @info.address.host, 3, 8, z];
        -- Append the string "B "
        -- String.AppendStringAndGrow[string, "B "L, z];
        -- Append the hexadecimal representation of info.address
        -- AppendNumberAndGrow[string, @info.address.host, 3, 16, z];
        -- Append the string "X "
        -- String.AppendStringAndGrow[string, "X "L, z];
        -- ****************************************************************** --
        -- Append the string " NET # "
        String.AppendStringAndGrow[string, " NET # "L, z];
        -- Append the net # --
        AppendDashedNumberAndGrow[string, @info.address.net, 2, 10, z];
        -- Append a blank --
        String.AppendStringAndGrow[string, " "L, z];
        -- Append the name of the server
        NSString.AppendToMesaString[temp, name.local];
        String.AppendStringAndGrow[string, temp, z];
        -- Append a CR --
        String.AppendStringAndGrow[string, "
    "L, z];
        found ← TRUE;
        END --AppendID-- ;

      SELECT index FROM
        listFS =>
          CHLookup.LookupFileserver[
            name, AppendID !
            CHLookup.Error => BEGIN found ← FALSE; CONTINUE; END; ];
        listPS =>
          CHLookup.LookupPrintserver[
            name, LOOPHOLE[AppendID] !
            CHLookup.Error => BEGIN found ← FALSE; CONTINUE; END; ];
        listMS =>
          CHLookup.LookupMailserver[
            name, LOOPHOLE[AppendID] !
            CHLookup.Error => BEGIN found ← FALSE; CONTINUE; END; ];
        ENDCASE => NULL;
      END --GetAndAppendID-- ;

    -- Set up the pattern to be used in the enumerations. --
    String.AppendChar[wildString, CH.wildCard];
    pattern ← [
      org: NSString.StringFromMesaString[toolData.strings[currOrganization]],
      domain: NSString.StringFromMesaString[toolData.strings[currDomain]],
      local: NSString.StringFromMesaString[wildString]];
    --The following code enumerates the servers found in the Clearinghouse,
    -- and appends their IDs to the appropriate strings.
    FOR index IN [listFS..listMS] DO
      string ← @toolData.strings[index];
      found ← CH.Enumerate[
        Authenticator.nullCredentials, Authenticator.firstVerifier, @pattern,
        (SELECT index FROM
           listFS => CHPIDs.ch3fileserver,
           listPS => CHPIDs.ch3printserver,
           ENDCASE => CHPIDs.ch3mailserver), GetAndAppendID].code = done;
      IF found THEN
        WHILE string[string↑.length - 1] = Ascii.SP
          OR string[string↑.length - 1] = Ascii.CR DO
          string↑.length ← string↑.length - 1; ENDLOOP  -- get rid of final CR
      ELSE String.AppendStringAndGrow[string, "none"L, z];
      ENDLOOP;
    END --AppendServers-- ;

  GetClearingHouse: PROCEDURE =
    BEGIN  --GetClearingHouse--
    CHAddr: System.NetworkAddress ← CHStubInternal.FindDomainAddr[
      CH.zeroMaxLengthNames];
    Format.NetworkNumber[GetTestEthernetID, CHAddr.net, productSoftware];
    Format.HostNumber[GetTestProcessorID, CHAddr.host, productSoftware];
    END --GetClearingHouse-- ;

  AppendNumberAndGrow: PROCEDURE [
    string: LONG POINTER TO LONG STRING, field: LONG POINTER, size: CARDINAL,
    radix: CARDINAL, z: UNCOUNTED ZONE] =
    BEGIN  --AppendNumberAndGrow--
    temp: LONG STRING ← [100];
    temp.length ← 0;
    ExtendedString.AppendNumber[field, size, radix, temp];
    String.AppendStringAndGrow[string, temp, z];
    END --AppendNumberAndGrow-- ;

  AppendDashedNumberAndGrow: PROCEDURE [
    string: LONG POINTER TO LONG STRING, field: LONG POINTER, size: CARDINAL,
    radix: CARDINAL, z: UNCOUNTED ZONE] =
    BEGIN  --AppendDashedNumberAndGrow--
    temp: LONG STRING ← [100];
    temp.length ← 0;
    ExtendedString.AppendNumber[field, size, radix, temp];
    FOR i: CARDINAL IN [0..temp.length) DO
      String.AppendCharAndGrow[string, temp[i], z];
      IF (temp.length - 1 - i) MOD 3 = 0 AND i # temp.length - 1 THEN
        String.AppendCharAndGrow[string, '-, z];
      ENDLOOP;
    END --AppendDashedNumberAndGrow-- ;

  -- Mainline code.

  Init[];

  END...