-- File: GateParameterAlto.mesa,  Last Edit: March 6, 1981  3:01 PM

DIRECTORY
  MiscOps USING [ReleaseDebuggerBitmap],
  SegmentDefs USING [FileHandle, MemoryConfig, GetMemoryConfig],
  StreamDefs USING [GetDiskStreamList, StreamHandle],

  CmFile USING [OpenSection, NextItem, GetNextToken, Close],
  FormSW USING [
    AllocateItemDescriptor, ClientItemsProcType, CommandItem, newLine, ProcType,
    StringItem],
  Put USING [Char, Decimal, Line, Number, Text],
  Runtime USING [IsBound],
  String USING [
    AppendChar, AppendDecimal, AppendNumber, AppendString, EquivalentString,
    InvalidNumber, StringToDecimal, StringToOctal, SubString,
    SubStringDescriptor],
  Process USING [Priority],
  Storage USING [FreeString, Expand, String],
  TajoMisc USING [SetState],
  TajoOps USING [UserCmFile],
  Tool USING [Create, MakeSWsProc, MakeFormSW],
  ToolWindow USING [TransitionProcType],
  UserTerminal USING [SetBackground],

  Clock USING [DisplayGoingOn, DisplayGoingOff],
  Indirect USING [GetParmFileName],
  Password USING [Check, Encrypt, Encrypted],
  Trouble USING [Bug, SetDisplayOnOffProcs, WrapTypescriptFile],

  AltoRam USING [CantFindFile, FileLooksCrufty, LoadRamAndBoot],
  AltoPRDefs USING [PRDriverVars, PRRouteIndex, GetPRDriverVars],
  AltoSlaDefs USING [
    LineNeedsPassword, RememberDialoutPassword, RememberDialinPassword],
  CommUtilDefs USING [GetEthernetHostNumber, LockCode],
  DriverDefs USING [
    CreateEthernetDriver, CreateChainedEthernetDriver, CreateEIADriver,
    CreateCommProcDriver, CreatePacketRadioDriver],
  GateDefs USING [typescript],
  PupDefs USING [
    AdjustBufferParms, UseAltoChecksumMicrocode, UsePrincOpsChecksumMicrocode];

GateParameterAlto: PROGRAM
  IMPORTS
    MiscOps, SegmentDefs, StreamDefs, CmFile, FormSW, Put, Runtime, String,
    Storage, TajoMisc, TajoOps, Tool, UserTerminal, AltoRam, AltoPRDefs,
    AltoSlaDefs, Clock, Indirect, Password, Trouble, CommUtilDefs, DriverDefs,
    GateDefs, PupDefs
  EXPORTS GateDefs =
  BEGIN

  LoadRam: PROCEDURE [fileName: STRING] =
    BEGIN
    SELECT TRUE FROM
      fileName.length = 0 =>
	Trouble.Bug["Please specify a Microcode file name."L];
      fileName.length # 0 =>
	BEGIN
	Put.Text[NIL, "Loading "L];
	Put.Text[NIL, fileName];
	Put.Text[NIL, "..."L];
	AltoRam.LoadRamAndBoot[
	  fileName !
	  AltoRam.CantFindFile => Trouble.Bug["Can't find microcode file."L];
	  AltoRam.FileLooksCrufty =>
	    Trouble.Bug["Microcode file looks crufty."L]];
	END;
      ENDCASE;
    Put.Line[NIL, "ok."L];
    END;

  GetDecimal: PROCEDURE [ss: String.SubString] RETURNS [CARDINAL] =
    BEGIN
    ENABLE String.InvalidNumber => Trouble.Bug["Decimal number expected."L];
    token: STRING = [100];
    IF ~CmFile.GetNextToken[ss, token] THEN SIGNAL String.InvalidNumber;
    RETURN[String.StringToDecimal[token]];
    END;

  GetOctal: PROCEDURE [ss: String.SubString] RETURNS [CARDINAL] =
    BEGIN
    ENABLE String.InvalidNumber => Trouble.Bug["Octal number expected."L];
    token: STRING = [100];
    IF ~CmFile.GetNextToken[ss, token] THEN SIGNAL String.InvalidNumber;
    RETURN[String.StringToOctal[token]];
    END;

  noLines, noBoard: WORD = 177765B;
  PrintHost: PROCEDURE [name: STRING, net, host, lines, board: CARDINAL] =
    BEGIN
    Put.Number[NIL, net, [8, FALSE, TRUE, 0]];
    Put.Char[NIL, '#];
    Put.Number[NIL, host, [8, FALSE, TRUE, 0]];
    Put.Char[NIL, '#];
    Put.Text[NIL, name];
    IF lines # noLines THEN
      BEGIN
      Put.Text[NIL, " with "L];
      Put.Decimal[NIL, lines];
      Put.Text[NIL, " lines"L];
      END;
    IF board # noBoard THEN
      BEGIN Put.Text[NIL, " on board "L]; Put.Decimal[NIL, board]; END;
    Put.Line[NIL, "."L];
    END;

  CheckHost: PROCEDURE [host: CARDINAL] =
    BEGIN
    IF host # CommUtilDefs.GetEthernetHostNumber[] THEN
      Trouble.Bug["Wrong Ethernet Host number"L];
    END;

  ScanParameterFile: PUBLIC PROCEDURE
    RETURNS [priority: Process.Priority, noOiscp: BOOLEAN] =
    BEGIN
    ramNeeded, ramLoaded: BOOLEAN ← FALSE;
    parmFileName: STRING ← NIL;
    sectionName: STRING = "Gateway"L;
    name, arg: STRING ← NIL;
    ss: String.SubStringDescriptor;

    priority ← 2;
    noOiscp ← TRUE;


    IF Runtime.IsBound[Indirect.GetParmFileName] THEN
      parmFileName ← Indirect.GetParmFileName[];
    IF parmFileName = NIL THEN parmFileName ← "GateParameter.txt"L;
    IF ~CmFile.OpenSection[parmFileName, sectionName] THEN
      BEGIN
      Message["Can't find [Gateway] section in "L, parmFileName];
      Message["I guess we are simply a BootServer"L];
      RETURN;
      END;

    DO
      [name, arg] ← CmFile.NextItem[];
      IF arg # NIL THEN ss ← [base: arg, offset: 0, length: arg.length];
      SELECT TRUE FROM
	name = NIL => EXIT;
	name[0] = '; => NULL;
	String.EquivalentString[name, "BUFFERS"L] => -- <number> (decimal)
	  BEGIN
	  buffers: CARDINAL ← GetDecimal[@ss];
	  PupDefs.AdjustBufferParms[buffers, 0];
	  MessageDecimal["Set number of buffers to "L, buffers];
	  END;
	String.EquivalentString[name, "EXPANDHEAP"L] => -- <pages> (decimal)
	  BEGIN
	  pages: CARDINAL ← GetDecimal[@ss];
	  Storage.Expand[pages];
	  MessageDecimal["Expanded the Heap by "L, pages, " pages"L];
	  END;
	String.EquivalentString[name, "KILL DEBUGGER BITMAP"L] =>
	  BEGIN
	  IF String.EquivalentString[arg, "TRUE"L] THEN
	    BEGIN
	    MiscOps.ReleaseDebuggerBitmap[];
	    Message["Released the debugger's bitmap"L];
	    END
	  ELSE Message["Didn't release the debugger's bitmap"L];
	  END;
	String.EquivalentString[name, "MICROCODE"L] => -- <filename>
	  BEGIN LoadRam[arg]; END;
	String.EquivalentString[name, "Activate OISCP Router"L] =>
	  BEGIN
	  IF String.EquivalentString[arg, "TRUE"L] THEN
	    BEGIN noOiscp ← FALSE; Message["Oiscp router will be activated"L]; END
	  ELSE Message["Didn't activate Oiscp router"L];
	  END;
	String.EquivalentString[name, "Priority"L] => -- <priority> (decimal)
	  BEGIN
	  priority ← GetDecimal[@ss];
	  MessageDecimal["Priority will be "L, priority];
	  END;
	String.EquivalentString[name, "TURN OFF DISPLAY"L] =>
	  BEGIN
	  IF String.EquivalentString[arg, "TRUE"L] THEN
	    BEGIN
	    [] ← TajoMisc.SetState[disconnected];
	    [] ← UserTerminal.SetBackground[black];
	    Message["Turning the Display OFF"L];
	    END
	  ELSE Message["Didn't turn the display OFF"L];
	  END;
	String.EquivalentString[name, "Typescript"L] => -- <pages>
	  BEGIN
	  pages: CARDINAL ← GetDecimal[@ss];
	  Trouble.WrapTypescriptFile[GateDefs.typescript, pages];
	  MessageDecimal[
	    "Typescript file will be trimmed at "L, pages, " pages"L];
	  END;

	-- Device things

	String.EquivalentString[name, "Ethernet"L] =>
	  BEGIN
	  net: CARDINAL ← GetOctal[@ss];
	  host: CARDINAL ← GetOctal[@ss];
	  board: CARDINAL ← GetOctal[@ss];
	  [] ← DriverDefs.CreateEthernetDriver[net, board];
	  PrintHost[" is an Ethernet"L, net, host, noLines, board];
	  CheckHost[host];
	  END;
	String.EquivalentString[name, "ChainedEthernet"L] =>
	  BEGIN
	  net: CARDINAL ← GetOctal[@ss];
	  host: CARDINAL ← GetOctal[@ss];
	  board: CARDINAL ← GetOctal[@ss];
	  [] ← DriverDefs.CreateChainedEthernetDriver[net, board];
	  PrintHost[" is a Chained Ethernet"L, net, host, noLines, board];
	  CheckHost[host];
	  END;
	String.EquivalentString[name, "EIA"L] =>
	  BEGIN
	  net: CARDINAL ← GetOctal[@ss];
	  host: CARDINAL ← GetOctal[@ss];
	  lines: CARDINAL ← GetOctal[@ss];
	  Trouble.SetDisplayOnOffProcs[
	    Clock.DisplayGoingOn, Clock.DisplayGoingOff];
	  [] ← DriverDefs.CreateEIADriver[host: host, net: net, lines: lines];
	  PrintHost[" is an EIA board"L, net, host, lines, noBoard];
	  END;
	String.EquivalentString[name, "CommProc"L] =>
	  BEGIN
	  net: CARDINAL ← GetOctal[@ss];
	  host: CARDINAL ← GetOctal[@ss];
	  lines: CARDINAL ← GetOctal[@ss];
	  [] ← DriverDefs.CreateCommProcDriver[
	    host: host, net: net, lines: lines];
	  PrintHost[" is a CommProc"L, net, host, lines, noBoard];
	  END;
	String.EquivalentString[name, "PacketRadio"L] =>
	  BEGIN
	  net: CARDINAL ← GetOctal[@ss];
	  host: CARDINAL ← GetOctal[@ss];
	  [] ← DriverDefs.CreatePacketRadioDriver[host: host, net: net];
	  PrintHost[" is a PacketRadio"L, net, host, noLines, noBoard];
	  END;
	String.EquivalentString[name, "ROUTE"L] =>
	  BEGIN
	  text: STRING = [100];
	  myp: POINTER TO AltoPRDefs.PRDriverVars ← AltoPRDefs.GetPRDriverVars[];
	  to: CARDINAL ← GetDecimal[@ss];
	  String.AppendNumber[text, to, 8];
	  String.AppendString[text, "]: "L];
	  FOR i: AltoPRDefs.PRRouteIndex IN AltoPRDefs.PRRouteIndex DO
	    n: WORD ← GetOctal[@ss];
	    myp↑.prRouteSetp[to][i] ← n;
	    String.AppendChar[text, ' ];
	    String.AppendNumber[text, n, 8];
	    ENDLOOP;
	  Message["PRRoute["L, text];
	  END;

	-- Password things

	String.EquivalentString[name, "LineNeedsPassword"L] =>
	  BEGIN
	  line: CARDINAL ← GetOctal[@ss];
	  AltoSlaDefs.LineNeedsPassword[line];
	  MessageOctal["Line "L, line, " needs a password"L];
	  -- Groan.  Do this here so we don't clutter up memory when it isn't needed.
	  CommUtilDefs.LockCode[Password.Check];
	  [] ← Password.Encrypt["foo"L, "foo"L];
	  -- Get it started and marked as in

	  END;
	String.EquivalentString[name, "DialinPassword"L] =>
	  BEGIN
	  e: Password.Encrypted;
	  p: POINTER ← @e;
	  text: STRING = [8*8];
	  FOR i: CARDINAL IN [0..SIZE[Password.Encrypted]) DO
	    (p + i)↑ ← GetOctal[@ss]; ENDLOOP;
	  FOR i: CARDINAL IN [0..SIZE[Password.Encrypted]) DO
	    IF i # 0 THEN String.AppendChar[text, ' ];
	    String.AppendNumber[text, (p + i)↑, 8];
	    ENDLOOP;
	  AltoSlaDefs.RememberDialinPassword[e];
	  Message["Dialin Password is "L, text];
	  END;
	String.EquivalentString[name, "SetupDialoutPassword"L] =>
	  BEGIN
	  IF String.EquivalentString[arg, "TRUE"L] THEN
	    BEGIN
	    SetupDialoutPasswordTool[];
	    Message["Setup Dialout Password Tool"L];
	    END
	  ELSE Message["Didn't Setup Dialout Password Tool"L];
	  END;

	ENDCASE =>
	  BEGIN
	  Put.Text[NIL, "****** Unrecognized keyword: "L];
	  Put.Line[NIL, name];
	  END;
      Storage.FreeString[name];
      Storage.FreeString[arg];
      ENDLOOP;

    CmFile.Close[parmFileName];
    IF ramNeeded AND ~ramLoaded THEN Trouble.Bug["Special Microcode required."L];
    END;

  -- User interface things for setting the dialout password

  password: STRING ← NIL;

  SetupDialoutPasswordTool: PROCEDURE =
    BEGIN
    [] ← Tool.Create[
      name: "Dialout Password"L, initialState: active, makeSWsProc: MakeSWs,
      clientTransition: ClientTransition];
    END;

  SetPassword: FormSW.ProcType =
    BEGIN AltoSlaDefs.RememberDialoutPassword[password]; END;

  MakeSWs: Tool.MakeSWsProc =
    BEGIN [] ← Tool.MakeFormSW[window: window, formProc: MakeForm]; END;

  MakeForm: FormSW.ClientItemsProcType =
    BEGIN
    nParams: CARDINAL = 2;
    items ← FormSW.AllocateItemDescriptor[nParams];
    items[0] ← FormSW.CommandItem[
      tag: "SetPassword"L, proc: SetPassword, place: FormSW.newLine];
    items[1] ← FormSW.StringItem[
      tag: "Password"L, string: @password, feedback: password];
    RETURN[items, TRUE];
    END;

  ClientTransition: ToolWindow.TransitionProcType =
    BEGIN
    SELECT TRUE FROM
      old = inactive => password ← Storage.String[20];
      new = inactive => Storage.FreeString[password];
      ENDCASE;
    END;

  -- xx

  MessageDecimal: PROCEDURE [
    one: STRING, num: CARDINAL, two, three: STRING ← NIL] =
    BEGIN
    text: STRING = [100];
    String.AppendString[text, one];
    String.AppendDecimal[text, num];
    IF two # NIL THEN String.AppendString[text, two];
    IF three # NIL THEN String.AppendString[text, three];
    String.AppendChar[text, '.];
    LogString[text];
    END;

  MessageOctal: PROCEDURE [one: STRING, num: CARDINAL, two, three: STRING ← NIL] =
    BEGIN
    text: STRING = [100];
    String.AppendString[text, one];
    String.AppendNumber[text, num, 8];
    IF two # NIL THEN String.AppendString[text, two];
    IF three # NIL THEN String.AppendString[text, three];
    String.AppendChar[text, '.];
    LogString[text];
    END;

  Message: PROCEDURE [one, two, three: STRING ← NIL] =
    BEGIN
    text: STRING = [100];
    String.AppendString[text, one];
    IF two # NIL THEN String.AppendString[text, two];
    IF three # NIL THEN String.AppendString[text, three];
    String.AppendChar[text, '.];
    LogString[text];
    END;

  LogString: PROCEDURE [text: STRING] = BEGIN Put.Line[NIL, text]; END;



  -- The rest of this module doesn't have anything to do with parameter files, but this is a handy location because it is already Alto specific.

  TryForMicrocodeChecksum: PROCEDURE =
    BEGIN
    config: SegmentDefs.MemoryConfig ← SegmentDefs.GetMemoryConfig[];
    SELECT TRUE FROM
      (config.AltoType = AltoIIXM AND
	(config.controlStore = RamandRom OR config.controlStore = Ram3k)) =>
	PupDefs.UseAltoChecksumMicrocode[];
      config.AltoType = D0, config.AltoType = Dorado =>
	PupDefs.UsePrincOpsChecksumMicrocode[];
      ENDCASE => Trouble.Bug["This program needs an XM Alto (or a D0)"L];
    END;

  --  AltoTajoControl leaves a dangling stream on User.cm

  FlushDanglingUserDotCm: PROCEDURE =
    BEGIN OPEN StreamDefs;
    userDotCmFile: SegmentDefs.FileHandle = TajoOps.UserCmFile[];
    FOR sh: StreamHandle ← GetDiskStreamList[], sh.link UNTIL sh = NIL DO
      WITH s: sh SELECT FROM
	Disk =>
	  BEGIN
	  IF s.file = userDotCmFile THEN
	    BEGIN -- This assumes that nobody else is reading User.cm
	    sh.destroy[sh];
	    EXIT;
	    END;
	  END;
	ENDCASE;
      ENDLOOP;
    END;

  -- initialization

  TryForMicrocodeChecksum[];
  FlushDanglingUserDotCm[];
  END.