-- PackDebugImpl.mesa  
--  last edited by JGS   on 17-Sep-82 14:09:18
--  last edited by Satterthwaite, January 12, 1983 11:31 am

DIRECTORY
  Alloc USING [AddNotify, DropNotify, Handle, Notifier],
  BcdDefs USING [
    CTIndex, CTNull, CTRecord, EVIndex, EVNull, FTIndex, FTNull, FTRecord, FTSelf,
    LFNull, MTIndex, MTRecord, Namee, NameRecord, NTIndex, NTRecord, NullName,
    SGIndex, VersionID, VersionStamp],
  BcdOps USING [CTHandle, MTHandle, NameString, SGHandle],
  CodePackProcs USING [ModuleIndex],
  CharIO USING [
    NumberFormat, PutChar, PutDecimal, PutNumber, PutOctal, PutString],
  HashOps USING [HTIndex, htNull, SubStringForHash],
  PackDebug,
  PackagerDefs USING [globalData, packsttype, packtreetype],
  ProcessingOrder USING [Enumerate],
  SemanticEntry USING [STIndex],
  SourceBcd USING [
    bcdBases, bcdHeader, bcdLimits, BcdTableLoc, CTreeIndex, nullCTreeIndex,
    EnumerateSons, Index, Kind, Link, Name, Prev, SharedProtoName,
    EnumerateModules, EnumerateModulesInConfig, EnumerateConfigs],
  String USING [SubString, SubStringDescriptor],
  Table USING [Base, Limit],
  Time USING [Append, Packed, Unpack],
  Tree: FROM "PackTree" USING [Index, Link, NodeName, Scan, nullIndex],
  TreeOps: FROM "PackTreeOps" USING [ScanSons];

PackDebugImpl: PROGRAM
    IMPORTS 
      Alloc, CharIO, HashOps, PackagerDefs, SourceBcd, Time,
      TreeOps, ProcessingOrder
    EXPORTS PackDebug =
  BEGIN  OPEN PackagerDefs;

  SubString: TYPE = String.SubString;
 
  table: Alloc.Handle ← NIL;
  
  stb, tb: Table.Base;

  UpdateBases: Alloc.Notifier = {
    tb     ← base[PackagerDefs.packtreetype];   -- parse tree table
    stb    ← base[PackagerDefs.packsttype]};     -- semantic entry table


 -- Initialization and Finalization

  Initialize: PUBLIC PROC = {
    table ← PackagerDefs.globalData.ownTable;
    table.AddNotify[UpdateBases]};

  Finalize: PUBLIC PROC = {
    table.DropNotify[UpdateBases];
    table ← NIL};
    

 -- Utility Writes

  WriteChar: PROC [c: CHARACTER] = {CharIO.PutChar[globalData.errorStream, c]};

  WriteString: PROC [s: STRING] = {CharIO.PutString[globalData.errorStream, s]};

  WriteSubString: PROC [ss: SubString] = {
    FOR i: CARDINAL IN [ss.offset..ss.offset+ss.length) DO
      WriteChar[ss.base[i]];
      ENDLOOP};

  WriteTime: PROC [t: Time.Packed] = {
    s: STRING ← [20];
    Time.Append[s, Time.Unpack[t]];
    WriteString[s]};

  Indent: PROC [n: CARDINAL] = {
    THROUGH [1..n/8] DO WriteChar['\t] ENDLOOP;
    THROUGH [1..n MOD 8] DO WriteChar[' ] ENDLOOP};

  Tab: PROC [n: CARDINAL] = {WriteChar['\n]; Indent[n]};


 -- Annotated printing

  WriteDecimal: PROC [id: STRING, n: INTEGER] = {
    IF id # NIL THEN WriteString[id];
    CharIO.PutDecimal[PackagerDefs.globalData.errorStream, n]};

  WriteOctal: PROC [id: STRING, n: UNSPECIFIED] = {
    IF id # NIL THEN WriteString[id];
    CharIO.PutOctal[PackagerDefs.globalData.errorStream, n]};

  WriteIndex: PROC [id: STRING, index: UNSPECIFIED] = {
    IF id # NIL THEN WriteString[id];
    PrintIndex[index]};


 -- Utility Prints

  PrintMachine: PROC [stamp: BcdDefs.VersionStamp] = {
    octal: CharIO.NumberFormat = [8,FALSE,FALSE,1];
    CharIO.PutNumber[PackagerDefs.globalData.errorStream, stamp.net, octal];
    WriteChar['#];
    CharIO.PutNumber[PackagerDefs.globalData.errorStream, stamp.host, octal];
    WriteChar['#]};

  PrintFileName: PROC [fti: BcdDefs.FTIndex] = {
    SELECT fti FROM
      BcdDefs.FTNull => WriteString["(null)"L];
      BcdDefs.FTSelf => WriteString["(self)"L];
      ENDCASE => WriteName[SourceBcd.bcdBases.ftb[fti].name]};

  PrintFileVersion: PROC [fti: BcdDefs.FTIndex] = {
    OPEN SourceBcd.bcdBases.ftb[fti];
    WriteChar['(];
    IF version.time = 0 THEN WriteString ["Null Version"L]
    ELSE
      BEGIN
      WriteTime[LOOPHOLE[version.time]];
      WriteChar[' ];  PrintMachine[version];
      END;
    WriteChar[')]};

  PrintIndex: PROC [index: UNSPECIFIED] = {
    WriteChar['[];
    IF index = Table.Limit-1
      THEN WriteString["Null"L]
      ELSE CharIO.PutDecimal[PackagerDefs.globalData.errorStream, index];
    WriteChar[']]};

  PrintNamee: PROC [n: BcdDefs.Namee] = {
    WriteChar['[];
    WITH n SELECT FROM
      config => {
        WriteString["cti: "L];
	CharIO.PutDecimal[PackagerDefs.globalData.errorStream, LOOPHOLE[cti]]}; 
      module => {
        WriteString["mti: "L];
	CharIO.PutDecimal[PackagerDefs.globalData.errorStream, LOOPHOLE[mti]]}; 
      import => {
        WriteString["impi: "L];
	CharIO.PutDecimal[PackagerDefs.globalData.errorStream, LOOPHOLE[impi]]}; 
      export => {
        WriteString["expi: "L];
	CharIO.PutDecimal[PackagerDefs.globalData.errorStream, LOOPHOLE[expi]]};
      ENDCASE; 
    WriteChar[']]};

  WriteNameFromTable: PROC [n: BcdDefs.Namee] = {
    OPEN BcdDefs;
    nti: NTIndex ← FIRST[NTIndex];
    UNTIL nti = SourceBcd.bcdLimits.nt DO
      IF SourceBcd.bcdBases.ntb[nti].item = n THEN { 
        WriteName[SourceBcd.bcdBases.ntb[nti].name];  EXIT};
      nti ← nti + SIZE[NTRecord];
      ENDLOOP};


 -- ********************** Parse Tree Printing ********************** 

  PrintTree: PUBLIC PROC = {
    WriteString["\n\n--Parse Tree--\n"L];
    PrintSubTree[PackagerDefs.globalData.root, 0];  WriteChar['\n];  WriteChar['\n]};

  PrintSubTree: PROC [t: Tree.Link, nBlanks: CARDINAL] = {
    OPEN Tree;

    Printer: Tree.Scan = {
      node: Tree.Index;
      Tab[nBlanks];
      WITH s: t SELECT FROM
        hash    => WriteHTI[s.index];
        symbol  => WriteSymbol[s.index]; 
        literal => WriteCodePackProcs[s.index]; 
        subtree => {
          node ← s.index;
          IF node = Tree.nullIndex THEN WriteString["<empty>"L]
          ELSE {
            OPEN tb[node];
            WriteNodeName[name];  PrintIndex[node];
            WriteOctal[", source["L, info];  WriteChar[']];
            SELECT name FROM
	      allComp, compItems, exceptItems, exceptPacks,
              itemsExceptPacks, exceptPacksItems, 
	      mainOfPL, evOfPL, catchOfPL => {
	        WriteString[", cp"L];  PrintIndex[cp];
                WriteString[", seg"L];  PrintIndex[seg]};
	      ENDCASE;
            IF attrs[$exceptMAIN] THEN SELECT name FROM
	      codePack, unnamedCodePack, discardCodePack =>
                WriteString[", except MAIN"L];
	      ENDCASE;
            IF attrs[$exceptEV] THEN SELECT name FROM
	      codePack, unnamedCodePack, discardCodePack =>
                WriteString[", except ENTRY VECTOR"L];
	      ENDCASE;
            IF attrs[$exceptCatch] THEN SELECT name FROM
	      codePack, unnamedCodePack, discardCodePack =>
                WriteString[", except CATCH CODE"L];
	      ENDCASE;
            IF attrs[$superceded] THEN SELECT name FROM
	      codeSeg, codePack, unnamedCodePack, merge, mergeFP,
	      discardCodePack => 
	        WriteString[", superceded"L];
	      ENDCASE;
            IF attrs[$placed] THEN SELECT name FROM
	      codeSeg, codePack, unnamedCodePack, merge, mergeFP,
              discardCodePack => 
	        WriteString[", placed"L];
	      ENDCASE;
            nBlanks ← nBlanks + 2;
            TreeOps.ScanSons[s, Printer];
            nBlanks ← nBlanks - 2}};
        ENDCASE};

    [] ← Printer[t]};

  WriteHTI: PROC [hti: HashOps.HTIndex] =
    BEGIN
    ss: String.SubString = @desc;
      desc: String.SubStringDescriptor;
    IF hti = HashOps.htNull
      THEN WriteString["(anonymous)"L]
      ELSE {HashOps.SubStringForHash[ss, hti];  WriteSubString[ss]};
    END;

  WriteNodeName: PROC [n: Tree.NodeName] =
    BEGIN
    NodePrintName: ARRAY Tree.NodeName OF STRING = [
      "list"L, 
      "code segment"L,
      "code pack"L, "unnamed code pack"L, "discard code pack"L,
      "frame pack"L,
      "merge segment"L, "merge frame pack"L,
      "allComp"L, "compItems"L, "exceptItems"L, "exceptPacks"L,
      "itemsExceptPacks"L, "exceptPacks&Items"L,
      "MAIN of pl"L, "EV of pl"L, "CATCH CODE of pl"L, 
      "component"L, "MAIN"L, "ENTRY VECTOR"L, "CATCH CODE"L,
      "none"L];
    WriteString[NodePrintName[n]];
    END;

  WriteSymbol: PROC [sym: SemanticEntry.STIndex] =
    BEGIN
    WriteIndex["symbol"L, sym];
    WriteChar[' ];  WriteHTI[stb[sym].hti];
    WriteIndex[", parse tree"L, stb[sym].treeNode];
    WITH stb[sym] SELECT FROM
      unknown => WriteString[" <unknown>"L];
      config => 
        BEGIN
        WriteIndex[", config: cti"L, cti];  
        WriteIndex[", cNode"L, cNode];
        END;
      module => 
        BEGIN
        WriteIndex[", module: mti"L, mti];  
        WriteIndex[", mNode"L, mNode];
        END;
      segment => 
        WriteString[", segment"L];
      codePack => 
        WriteString[", code pack"L];
      framePack => 
        WriteString[", frame pack"L];
      ENDCASE;
    END;

  WriteCodePackProcs: PROC [mi: CodePackProcs.ModuleIndex] =
    BEGIN
    WriteIndex["code pack procs"L, mi];
    END;


-- ********************** Source Bcd Table Printing **********************

  PrintSourceBcd: PUBLIC PROC =
    BEGIN
    WriteString["\n\n--Source Bcd--\n"L];
    PrintHeader[];
    WriteString["Configurations:"L];
    SourceBcd.EnumerateConfigs[PrintConfig];
    WriteString["\n\nModules:"L];
    SourceBcd.EnumerateModules[PrintModule];
    WriteChar['\n];
    PrintFiles[];
    END;
    
  PrintHeader: PROC =
    BEGIN OPEN bcd: SourceBcd.bcdHeader;
    WriteString["  Configured "L];  WriteTime[LOOPHOLE[bcd.version.time]];
    IF bcd.source # BcdDefs.NullName THEN {
      WriteString[" from "L];  WriteName[bcd.source]};
    WriteString[" by "L];  PrintMachine[bcd.version];
    IF bcd.versionIdent # BcdDefs.VersionID THEN
      WriteDecimal["  Obsolete VersionID = "L, bcd.versionIdent];
    WriteString["\n  Configured by "L];  WriteTime[LOOPHOLE[bcd.creator.time]];
    WriteChar[' ];  PrintMachine[bcd.creator];
    WriteString["\n  "L];
    IF ~bcd.definitions THEN WriteChar['~];  
    WriteString["definitions, "L];
    IF ~bcd.repackaged THEN WriteChar['~];  
    WriteString["repackaged, "L];
    IF ~bcd.tableCompiled THEN WriteChar['~];  
    WriteString["tableCompiled"L];
    WriteDecimal["\n\n  Configurations: "L, bcd.nConfigs];
    WriteDecimal[", Modules: "L, bcd.nModules];
    WriteDecimal[", Imports: "L, bcd.nImports];
    WriteDecimal[", Exports: "L, bcd.nExports];
    WriteDecimal[", Dummy: "L, bcd.firstdummy];
    WriteDecimal[", #Dummies: "L, bcd.nDummies];
    WriteChar['\n];  WriteChar['\n];
    END;

  PrintConfig: PROC [cti: BcdDefs.CTIndex] RETURNS [stop: BOOLEAN] = {
    OPEN BcdDefs;
    config: BcdOps.CTHandle = @SourceBcd.bcdBases.ctb[cti];
    Tab[2];
    WriteName[config.name];  PrintIndex[cti];
    IF config.namedInstance THEN {
      WriteString[", instance: "L];  WriteNameFromTable[[config[cti]]]};
    WriteString[", file: "L];  PrintFileName[config.file];
    PrintIndex[config.file];
    IF config.config # CTNull THEN {
      WriteString[", parent: "L];  
      WriteName[SourceBcd.bcdBases.ctb[config.config].name];
      PrintIndex[config.config]};
    IF config.nControls # 0 THEN {
      WriteString[", controls:"L];
      FOR i: CARDINAL IN [0..config.nControls) DO
        IF i MOD 6 = 0 THEN Tab[6] ELSE WriteChar[' ];
        WriteNameFromTable[config.controls[i]];
        PrintNamee[config.controls[i]];
        IF i+1 # config.nControls THEN WriteChar[',];
        ENDLOOP};
    RETURN[FALSE]};

  PrintModule: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] = {
    OPEN BcdDefs;
    module: BcdOps.MTHandle = @SourceBcd.bcdBases.mtb[mti];
    Tab[2];
    WriteName[module.name];  PrintIndex[mti];
    IF module.namedInstance THEN
      {WriteString[", instance: "L];  WriteNameFromTable[[module[mti]]]};
    WriteString[", file: "L];  
    PrintFileName[module.file];  PrintIndex[module.file];
    IF module.config # CTNull THEN {
      WriteString[", config: "L];
      WriteName[SourceBcd.bcdBases.ctb[module.config].name];
      PrintIndex[module.config]};
    Tab[4];
    WriteDecimal["framesize: "L, module.framesize];
    WriteDecimal[", gfi: "L, module.gfi];
    WriteDecimal[", ngfi: "L, module.ngfi];
    WriteString[", links: "L];
    WriteString[
      (SELECT module.linkLoc FROM
        frame   => "frame"L,
	code    => "code"L,
	ENDCASE => "dontcare"L)];
    Tab[4];
    WriteString["code: "L];  PrintSegment[module.code.sgi];
    WriteOctal[", offset: "L, module.code.offset];
    WriteOctal[", length: "L, module.code.length];
    IF module.code.linkspace THEN WriteString [", space available for links"L];
    Tab[4];
    WriteString["symbols: "L];  PrintSegment[module.sseg];
    IF module.variables # EVNull THEN {
      Tab[4];  WriteIndex["variables: "L, module.variables]};
    Tab[4];
    WriteDecimal[
      "number of links: "L, 
      (IF module.links = LFNull THEN 0
       ELSE SourceBcd.bcdBases.lfb[module.links].length)];
    Tab[4];
    IF ~module.packageable THEN WriteChar['~];
    WriteString["packageable, "L];
    IF ~module.tableCompiled THEN WriteChar['~];
    WriteString["tableCompiled, "L];
    IF ~module.residentFrame THEN WriteChar['~];
    WriteString["residentFrame"L];
    RETURN[FALSE]};

  PrintSegment: PROC [sgi: BcdDefs.SGIndex] = {
    sd: BcdOps.SGHandle = @SourceBcd.bcdBases.sgb[sgi];
    PrintFileName[sd.file];  PrintIndex[sgi];
    WriteDecimal[", [base: "L, sd.base]; WriteDecimal[", pages: "L, sd.pages];
    IF sd.extraPages # 0 THEN WriteDecimal["+"L, sd.extraPages];
    WriteChar[']]};

  PrintFiles: PROC = {
    OPEN BcdDefs;
    fti: FTIndex ← FIRST[FTIndex];
    WriteString["\nFiles:"L];
    UNTIL fti = SourceBcd.bcdLimits.ft DO 
      PrintFile[fti]; 
      fti ← fti + SIZE[FTRecord] 
      ENDLOOP;
    WriteChar['\n]};

  PrintFile: PROC [fti: BcdDefs.FTIndex] = {
    OPEN SourceBcd.bcdBases.ftb[fti];
    Tab[2];
    SELECT fti FROM
      BcdDefs.FTNull => WriteString["(null)"L];
      BcdDefs.FTSelf => WriteString["(self)"L];
      ENDCASE => {
	WriteName[name];  PrintIndex[fti];
	WriteString[", version: "L];  PrintFileVersion[fti]}};

  WriteName: PROC [n: BcdDefs.NameRecord] = {
    ssd: String.SubStringDescriptor ← [
      base: @SourceBcd.bcdBases.ssb.string, 
      offset: n, 
      length: SourceBcd.bcdBases.ssb.size[n]];
    WriteSubString[@ssd]};


 -- ********************** Configuration Tree Printing **********************

  PrintConfigTree: PUBLIC PROC [root: SourceBcd.CTreeIndex] = {
    WriteString["\n\n--Configuration Tree--\n"L];    
    IF root = SourceBcd.nullCTreeIndex THEN WriteString[" <Empty>"L]
    ELSE {
      nBlanks: CARDINAL ← 1;
      
      WriteSubConfigTree: PROC [node: SourceBcd.CTreeIndex] RETURNS [BOOL←FALSE] = {
	index: SourceBcd.BcdTableLoc = node.Index;
	Tab[nBlanks];
	IF node.Kind = $instance THEN {WriteName[node.Name[$instance]]; WriteChar[':]};
	WriteName[node.Name[$prototype]];  PrintIndex[node];
	WriteChar[' ];
	IF ~node.SharedProtoName THEN WriteChar['~];
	WriteString["pNameTwice"L];
	WITH index SELECT FROM
	  module => WriteIndex[", module"L, mti];
	  config => WriteIndex[", config"L, cti];
	  ENDCASE;
	WriteIndex[", Link: i"L, node.Link[$instance]];
	WriteIndex[", p"L, node.Link[$prototype]];
	WriteIndex[", Prev: i"L, node.Prev[$instance]];
	WriteIndex[", p"L, node.Prev[$prototype]];
	nBlanks ← nBlanks+2;
	node.EnumerateSons[WriteSubConfigTree];
	nBlanks ← nBlanks-2};

      [] ← WriteSubConfigTree[root]; WriteChar['\n]};
    WriteChar['\n]};


 -- ******************** Processing Order Printing ********************

  PrintProcessingOrder: PUBLIC PROC [root: SourceBcd.CTreeIndex] =
    BEGIN
    WriteString["\n\n--Processing Order--\n"L];
    SourceBcd.EnumerateModulesInConfig[
      kind: prototype,
      configTreeNode: root,
      userProc: PrintOneModulesOrder];
    WriteChar['\n];
    END;

  PrintOneModulesOrder: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] =
    BEGIN
    printCount: CARDINAL ← 0;

    PrintOneCDNode: PROC [cdNode: Tree.Index] RETURNS [stop: BOOLEAN] =
      BEGIN  -- print one component description node to be processed for mti
      IF (printCount ← printCount+1) > 10 THEN 
        {WriteString["\n  "L];  printCount ← 1}
      ELSE WriteString[" "L];
      PrintIndex[cdNode];
      RETURN[FALSE];
      END;
  
    Tab[0];
    WriteName[SourceBcd.bcdBases.mtb[mti].name];  
    PrintIndex[mti];  WriteString[": "L];  
    ProcessingOrder.Enumerate[mti, PrintOneCDNode];
    RETURN[FALSE];
    END;

  END.