-- DumpCold.mesa; modified by Bruce,  October 25, 1980  10:00 PM

DIRECTORY
  Ascii USING [SP],
  DebugFormat USING [BitAddress, Fob, Foo, OctalFormat],
  DebugOps USING [Display, DisplayFoo, Foo, FooProc, Interpret, LongREAD, UserAborted],
  DI USING [
    BitAddress, CheckClass, CSEIndex, DerefProcDesc, Foo, GetControlLink,
    GetDesc, GetLongDesc, LongDesc, Normalize, NotAProcedure, SEIndex,
    TransferSEIndex, TypeForSe, FindField, GetValue, SequenceSEIndex],
  DOutput USING [Char, Decimal, Number, Octal, Text],
  Dump USING [
    ArrayHandle, ArrayInfo, BadNum, HashVal, LongNum, Printer, PrintRec, PrintUCS,
    NullVariant],
  Frames USING [Invalid],
  Gf USING [Display, DisplayInMsg, FrameGfi, Handle, OldLink, Validate],
  DHeap USING [AllocFob],
  Init USING [],
  Inline USING [LongDivMod, LongMult],
  Lookup USING [Signal],
  MachineDefs USING [WordLength],
  Pc USING [LinkToIsei],
  PrincOps USING [ControlLink, Port, ProcDesc, SignalDesc],
  State USING [GetGS, GSHandle],
  Storage USING [Node],
  SymbolOps USING [BitsPerElement, Cardinality],
  SymbolPack,
  Symbols USING [
    ArraySEIndex, CSEIndex, HTIndex, HTNull, ISEIndex, ISENull, SEIndex, SENull,
    RecordSEIndex, seType, TransferMode, TypeClass],
  Table USING [AddNotify, Base, DropNotify, Notifier],
  TajoMisc USING [initialToolStateDefault],
  Types USING [Equivalent, Handle],
  UserInput USING [ResetUserAbort, userAbort];

DumpCold: PROGRAM
  IMPORTS DebugOps, DI, DOutput, Dump, Frames, Gf, DHeap, Inline, Lookup,
    Pc, State, Storage, SymbolOps, MyBase: SymbolPack, Table, TajoMisc, Types, UserInput
  EXPORTS Dump, Init =
BEGIN OPEN DI, Dump, SymbolOps, Symbols;

TriedToPrintWrongType: ERROR [foo: Foo] = CODE;
BadTag: ERROR = CODE;

seb: Table.Base;
data: State.GSHandle ← State.GetGS[];
printers: PUBLIC POINTER TO PrintRec ← NIL;
entryDepth: CARDINAL ← 0;

ArrayLimit: PUBLIC CARDINAL ← LAST[CARDINAL];

Enter: PROCEDURE = {
  IF entryDepth = 0 THEN Table.AddNotify[Notify];
  entryDepth ← entryDepth + 1};

Exit: PROC = {IF (entryDepth ← entryDepth-1) = 0 THEN Table.DropNotify[Notify]};

Notify: Table.Notifier = {seb ← base[seType]};

AddPrinter: PUBLIC PROCEDURE [type: STRING, proc: Printer] =
  BEGIN
  Type: DebugOps.FooProc = {p.tsei ← f.tsei};
  p: POINTER TO PrintRec ← Storage.Node[SIZE[PrintRec]];
  p↑ ← [
    link: printers, sym: type, tsei: SENull, proc: proc];
  IF TajoMisc.initialToolStateDefault # inactive THEN
    DebugOps.Interpret[p.sym, Type ! ANY => {p.tsei ← SENull; CONTINUE}];
  printers ← p;
  END;

ResetPrinters: PUBLIC PROCEDURE =
  BEGIN
  Type: DebugOps.FooProc = {p.tsei ← f.tsei};
  p: POINTER TO PrintRec;
  FOR p ← printers, p.link UNTIL p = NIL DO
    DebugOps.Interpret[p.sym, Type ! ANY => {p.tsei ← SENull; CONTINUE}];
    ENDLOOP;
  END;

CompareSes: PUBLIC PROC [sei1, sei2: Symbols.SEIndex] RETURNS [print: BOOLEAN] =
  BEGIN
  left: Types.Handle ← [LOOPHOLE[MyBase],TypeForSe[sei1]];
  right: Types.Handle ← [LOOPHOLE[MyBase],TypeForSe[sei2]];
  RETURN[Types.Equivalent[type1: left, type2: right]];
  END;

Sequence: PUBLIC PROC [f: Foo, pad: CARDINAL, sei: DI.SequenceSEIndex,
    variant: PROC RETURNS [Symbols.RecordSEIndex] ← NullVariant] =
  BEGIN
  tag: Foo;
  ai: ArrayInfo;
  ba: BitAddress;
  words: CARDINAL;
  Enter[];
  IF ~seb[sei].controlled THEN {DOutput.Text["(?) ..."L]; Exit[]; RETURN};
  tag ← DI.FindField[f,pad,seb[sei].tagSei];
  IF tag.bits + tag.addr.offset > MachineDefs.WordLength THEN ERROR BadTag;
  ba ← [base: tag.addr.base, offset: ];
  [words, ba.offset] ← Normalize[tag.addr.offset+tag.bits];
  ba.base ← tag.words + ba.base + words;
  DI.GetValue[tag];
  ai ← [start: 0, stop: tag.addr.base↑, length: tag.addr.base↑, addr: ba,
    packing: SymbolOps.BitsPerElement[seb[sei].componentType, seb[sei].packed],
    type: seb[sei].componentType];
  Elements[@ai ! DebugOps.UserAborted => {ControlDel[]; CONTINUE}; UNWIND => Exit[]];
  Exit[];
  END;

Array: PUBLIC PROCEDURE [f: Foo] =
  BEGIN
  sei: ArraySEIndex ← CheckClass[array, f];
  Enter[];
  ArrayCommon[sei, f.addr, Cardinality[seb[sei].indexType] ! UNWIND => Exit[]];
  Exit[];
  END;

ArrayCommon: PROCEDURE [tsei: SEIndex, ba: BitAddress, length: CARDINAL] =
  BEGIN
  csei: CSEIndex ← DI.TypeForSe[tsei];
  sei: ArraySEIndex;
  ai: ArrayInfo;
  Enter[];
  IF seb[csei].typeTag = array THEN sei ← LOOPHOLE[csei]
    ELSE {Exit[]; ERROR TriedToPrintWrongType[NIL]};
  ai ← [start: 0, stop: length, length: length, addr: ba,
    packing: SymbolOps.BitsPerElement[seb[sei].componentType, seb[sei].packed],
    type: seb[sei].componentType];
  Elements[@ai ! DebugOps.UserAborted => {ControlDel[]; CONTINUE}; UNWIND => Exit[]];
  Exit[];
  END;

LongArrayDesc: PUBLIC PROCEDURE [f: Foo] =
  BEGIN OPEN DOutput;
  d: DI.LongDesc;
  sei: ArraySEIndex;
  [d,sei] ← DI.GetLongDesc[f];
  Text["DESCRIPTOR["L]; LongNum[d.base, [pointer[]]]; Char[',];
  MyDecimal[d.length]; Char[']];
  IF d.base = NIL THEN RETURN;
  ArrayCommon[sei, [d.base,0], d.length];
  END;

ArrayDesc: PUBLIC PROCEDURE [f: Foo] =
  BEGIN OPEN DOutput;
  d: DI.LongDesc;
  sei: ArraySEIndex;
  [d,sei] ← DI.GetDesc[f];
  Text["DESCRIPTOR["L]; LongNum[d.base, [pointer[]]]; Char[',];
  MyDecimal[d.length]; Char[']];
  IF d.base = NIL THEN RETURN;
  ArrayCommon[sei, [d.base,0], d.length];
  END;

Elements: PUBLIC PROCEDURE [ai: ArrayHandle, printAll: BOOLEAN ← FALSE] =
  BEGIN OPEN DOutput;
  i: CARDINAL;
  f: Foo;
  fob: DebugFormat.Fob ← [
    hti: HTNull,
    indent: 0, xfer: FALSE,
    tsei: ai.type,
    typeOnly: FALSE,
    there: TRUE,
    addr:, words:, bits:, nesting: 0];
  [fob.words, fob.bits] ← Normalize[ai.packing];
  fob.addr ← CalculateAddr[ai, ai.start];
  Char['(]; MyDecimal[ai.length]; Text[")["L];
  FOR i IN [ai.start..ai.stop) DO
    IF i # ai.start THEN Text[", "L];
    f ← DHeap.AllocFob[];
    f↑ ← fob;
    IF i = 3 AND ~printAll AND ai.length > ArrayLimit THEN
      BEGIN
      f.addr ← CalculateAddr[ai, ai.stop-1];
      Text["..., "L];
      DebugOps.Display[f,TRUE];
      EXIT;
      END;
    DebugOps.Display[f,TRUE];
    NextAddr[@fob,ai.packing];
    IF UserInput.userAbort THEN {ControlDel[]; RETURN};
    ENDLOOP;
  Char[']];
  END;

CalculateAddr: PUBLIC PROC [ai: ArrayHandle, n: CARDINAL] RETURNS [ba: BitAddress] =
  BEGIN OPEN Inline, MachineDefs;
  words, offset: CARDINAL;
  ba.useStack ← ai.addr.useStack;
  [words, offset] ← Normalize[ai.packing];
  ba.base ← ai.addr.base + LongMult[words, n];
  [words, ba.offset] ← LongDivMod[LongMult[offset, n], WordLength];
  ba.base ← ba.base + words;
  [words, ba.offset] ← Normalize[ba.offset+ai.addr.offset];
  ba.base ← ba.base + words;
  RETURN
  END;

NextAddr: PROCEDURE [f: Foo, packing: CARDINAL] =
  BEGIN
  words, bits: CARDINAL;
  [words, bits] ← Normalize[packing];
  IF bits = 0 THEN BEGIN f.addr.base ← f.addr.base + words; RETURN END;
  IF bits + f.addr.offset = 16 THEN
    BEGIN f.addr.base ← f.addr.base + 1; f.addr.offset ← 0 END
  ELSE f.addr.offset ← f.addr.offset + bits;
  RETURN;
  END;

BadDesc: PROC [cl: PrincOps.ControlLink] = {
  IF cl.gfi = 0 OR ~cl.tag THEN BadNum[Gf.OldLink[cl]]
  ELSE {
    DOutput.Char['[]; DOutput.Octal[Gf.OldLink[cl]]; DOutput.Char[']]}};

XferName: PUBLIC PROC [cl: PrincOps.ProcDesc, isei: ISEIndex] =
  {IF isei = ISENull THEN BadDesc[cl] ELSE HashVal[isei]};

XferFrame: PUBLIC PROC [cl: PrincOps.ProcDesc] =
  BEGIN Gf.DisplayInMsg[Gf.FrameGfi[cl.gfi], "module"L] END;

Sig: PUBLIC PROC [cl: PrincOps.ProcDesc] =
  BEGIN
  IF data.signal = cl THEN Dump.PrintUCS[]
  ELSE {XferName[cl, Lookup.Signal[cl]]; XferFrame[cl]};
  END;

Xfer: PUBLIC PROCEDURE [f: Foo] =
  BEGIN ENABLE UNWIND => Exit[];
  sei: TransferSEIndex ← CheckClass[transfer, f];
  cl: PrincOps.ControlLink;
  Enter[];
  IF seb[sei].mode # process THEN cl ← DI.GetControlLink[f];
  SELECT seb[sei].mode FROM
    proc => Proc[cl];
    port => Port[cl];
    signal => {DOutput.Text["SIGNAL "L]; Sig[LOOPHOLE[cl]]};
    error => {DOutput.Text["ERROR "L]; Sig[LOOPHOLE[cl]]};
    process => {DI.GetValue[f]; Process[f.addr.base↑]};
    program => Prog[cl];
    ENDCASE => ERROR TriedToPrintWrongType[f];
  Exit[];
  END;

Proc: PUBLIC PROC [cl: PrincOps.ControlLink] =
  BEGIN
  DOutput.Text["PROCEDURE "L];
    BEGIN ENABLE Frames.Invalid => GOTO bad;
    cl ← DI.DerefProcDesc[cl ! DI.NotAProcedure => GOTO bad];
    XferName[LOOPHOLE[cl], Pc.LinkToIsei[cl]];
    XferFrame[LOOPHOLE[cl]];
    EXITS bad => BadDesc[cl];
    END;
  END;

Port: PUBLIC PROC [cl: PrincOps.ControlLink] =
  BEGIN OPEN DOutput;
  Text["PORT ["L];
  Octal[cl.port.in]; Text[", "L]; Octal[cl.port.out]; Char[']];
  END;

Process: PUBLIC PROC [psb: UNSPECIFIED] =
  {DOutput.Text["PROCESS ["L]; DOutput.Octal[psb]; DOutput.Char[']]};

Prog: PUBLIC PROC [gf: UNSPECIFIED] =
  BEGIN
  IF Gf.Validate[gf] THEN Gf.Display[gf,"PROGRAM"L] ELSE BadDesc[gf];
  END;

Opaque: PUBLIC PROCEDURE [f: Foo] =
  BEGIN
  osei: Symbols.CSEIndex ← CheckClass[opaque, f];
  proc: PROCEDURE [LONG POINTER] RETURNS [UNSPECIFIED] ←
    IF f.there THEN DebugOps.LongREAD ELSE ReadMem;
  Enter[];
  WITH seb[osei] SELECT FROM
    opaque =>
      BEGIN
      IF id # Symbols.ISENull THEN HashVal[id];
      IF lengthKnown AND length # 0 THEN 
	BEGIN
	n: CARDINAL;
	size: CARDINAL = length/MachineDefs.WordLength;
	DOutput.Char['(]; DOutput.Octal[size]; DOutput.Text["):"L];
	FOR j: CARDINAL IN [0..size) DO
	  DOutput.Char[' ];
	  DOutput.Number[n ← proc[f.addr.base+j], DebugFormat.OctalFormat];
	  DOutput.Char[IF n ~IN[0..7] THEN 'B ELSE Ascii.SP];
	  IF UserInput.userAbort THEN {ControlDel[]; RETURN};
	  ENDLOOP;
	END;
      END;
    ENDCASE;
  Exit[];
  END;

ReadMem: PUBLIC PROC [p: LONG POINTER] RETURNS [UNSPECIFIED] = {RETURN[p↑]};

MyDecimal: PROCEDURE [u: UNSPECIFIED] = INLINE {DOutput.Decimal[LOOPHOLE[u,INTEGER]]};

ControlDel: PROC = {UserInput.ResetUserAbort[]; DOutput.Text[" ... aborted"L]};
  
ModeName: PUBLIC PROCEDURE [n: TransferMode] =
  BEGIN
  ModePrintName: ARRAY TransferMode OF STRING = ["PROCEDURE"L, "PORT"L,
    "SIGNAL"L, "ERROR"L, "PROCESS"L, "PROGRAM"L, "NONE"L];
  DOutput.Text[ModePrintName[n]]
  END;

END.