-- PackListImpl.mesa  
--   Last edited by Lewis on 27-Oct-81 15:12:11
--   Last edited by Satterthwaite, December 29, 1982 11:50 am

DIRECTORY
  Alloc USING [AddNotify, DropNotify, Handle, Notifier],
  BcdDefs USING [MTIndex, Namee, NameRecord, NTIndex, NTRecord],
  CodePackProcs USING [
    AnyProcs, EnumerateSegments, EnumerateCodePacks, EnumerateModules,
    EnumerateProcs, ModuleIndex, SubStringForOPIndex],
  CharIO USING [PutChar, PutString],
  FramePackModules USING [EnumerateFramePacks, EnumerateModules],
  HashOps USING [HTIndex, htNull, SubStringForHash],
  PackagerDefs USING [globalData, GlobalData, packtreetype],
  PackList,
  PackageSymbols USING [OPIndex],
  SourceBcd USING [
    bcdBases, bcdLimits, BcdTableLoc, CTreeIndex, Father, Index, IsTableCompiled,
    LookupName, Name, nullCTreeIndex, Prev],
  String USING [SubString, SubStringDescriptor],
  Table USING [Base],
  Time USING [Append, Current, Packed, Unpack],
  Tree: FROM "PackTree" USING [Index, Link, NodeName, nullIndex];

PackListImpl: PROGRAM
    IMPORTS 
      Alloc, CharIO, HashOps, PackagerDefs, SourceBcd, Time,
      CodePackProcs, FramePackModules
    EXPORTS PackList =
  BEGIN

  PackListError: ERROR = CODE;

  SubString: TYPE = String.SubString;
  SubStringDescriptor: TYPE = String.SubStringDescriptor;
 
  gd: PackagerDefs.GlobalData ← NIL;
  table: Alloc.Handle ← NIL;

  tb: Table.Base;
  
  UpdateBases: Alloc.Notifier = {tb ← base[PackagerDefs.packtreetype]};   -- parse tree table


 -- ********************* Print code and frame packs *********************

  Print: PUBLIC PROC = {
    gd ← PackagerDefs.globalData;
    table ← gd.ownTable;
    table.AddNotify[UpdateBases];
    PrintHeading[];
    PrintCodePackProcs[];
    PrintFramePackModules[];
    table.DropNotify[UpdateBases];
    table ← NIL;  gd ← NIL};

  PrintHeading: PROC = {
    WriteString["-- File "L];  WriteString[gd.packListFileName];
    WriteString["\n-- Created by Packager from "L]; 
    WriteString[gd.packName]; 
    WriteString[" on "L]; 
    WriteTime[Time.Current[]];  WriteChar['\n]}; 


 -- ********************* Code Pack Procedure Printing *********************

  PrintCodePackProcs: PROC =
    {CodePackProcs.EnumerateSegments[PrintOneCodeSegment]};

  PrintOneCodeSegment: PROC [segNode: Tree.Index] RETURNS [stop: BOOLEAN] =
    BEGIN
    IF segNode # Tree.nullIndex THEN 
      BEGIN
      WriteChar['\n];
      WITH tb[segNode].son[1] SELECT FROM
	hash => WriteHTI[index];
	ENDCASE;
      WriteString[": SEGMENT =\n"L]; 
      WriteString["  BEGIN\n"L];  
      CodePackProcs.EnumerateCodePacks[segNode, PrintOneCodePack];
      WriteString["  END;\n"L];
      END;  
    RETURN[FALSE]; 
    END;

  PrintOneCodePack: PROC [cpNode: Tree.Index] RETURNS [stop: BOOLEAN] =
    BEGIN
    IF cpNode # Tree.nullIndex THEN  
      BEGIN
      WriteString["\n  "L];
      WITH tb[cpNode].son[1] SELECT FROM
	hash => WriteHTI[index];
	ENDCASE;
      IF tb[cpNode].name = discardCodePack THEN 
        WriteString[": DISCARD CODE PACK ="L]
      ELSE WriteString[": CODE PACK ="L];
      WriteString["\n    BEGIN\n"L];  
      CodePackProcs.EnumerateModules[cpNode, PrintOneCodePackModule];
      WriteString["    END;\n"L];  
      END;  
    RETURN[FALSE]; 
    END; 

  firstProc: BOOLEAN;
  numProcsPrinted: CARDINAL;

  PrintOneCodePackModule: PROC [
        mti: BcdDefs.MTIndex, module: CodePackProcs.ModuleIndex] 
      RETURNS [stop: BOOLEAN] =
    BEGIN
    IF CodePackProcs.AnyProcs[module] THEN
      BEGIN
      WriteString["    "L];
      PrintModulePrototypeName[mti];  
      WriteString["[\n"L];
      firstProc ← TRUE;  numProcsPrinted ← 0;
      WriteString["      "L];
      CodePackProcs.EnumerateProcs[module, PrintCodePackProc];
      WriteString["];\n"L];  
      END
    ELSE IF SourceBcd.IsTableCompiled[mti] THEN 
      BEGIN
      WriteString["    "L];
      PrintModulePrototypeName[mti];  
      WriteString[";\n"L];  
      END;
    RETURN[FALSE]; 
    END; 

  PrintModulePrototypeName: PROC [module: BcdDefs.MTIndex] =
    BEGIN
    name: BcdDefs.NameRecord;
    firstNode, n: SourceBcd.CTreeIndex;
    
    WriteQualifiedName: PROC [cNode: SourceBcd.CTreeIndex] =
      BEGIN
      IF cNode.Father # SourceBcd.nullCTreeIndex THEN
        {WriteQualifiedName[cNode.Father];  WriteChar['.]};
      WriteName[cNode.Name[$prototype]];
      END;

    name ← SourceBcd.bcdBases.mtb[module].name;
    firstNode ← SourceBcd.LookupName[name, prototype];
    IF firstNode = SourceBcd.nullCTreeIndex THEN ERROR PackListError;
    IF firstNode.Prev[$prototype] = SourceBcd.nullCTreeIndex THEN
      WriteName[name]
    ELSE
      BEGIN  -- name is not unique, so find and print correct qualified name
      FOR n ← firstNode, n.Prev[$prototype] UNTIL n = SourceBcd.nullCTreeIndex DO
        index: SourceBcd.BcdTableLoc = n.Index;
        WITH index SELECT FROM
          module => IF mti = module THEN {WriteQualifiedName[n];  RETURN};
          ENDCASE;
        ENDLOOP;
      ERROR PackListError;  -- could not find the module to print out
      END;
    END; 

  PrintCodePackProc: PROC [
      opi: PackageSymbols.OPIndex] RETURNS [stop: BOOLEAN] =
    BEGIN
    procIdSS: String.SubString ← @procIdSSDesc;
      procIdSSDesc: String.SubStringDescriptor;
    IF ~firstProc THEN WriteString[", "L];
    firstProc ← FALSE;
    IF (numProcsPrinted ← numProcsPrinted+1) > 5 THEN 
      {WriteString["\n      "L];  numProcsPrinted ← 1};
    CodePackProcs.SubStringForOPIndex[procIdSS, opi]; 
    WriteSubString[procIdSS];
    RETURN[FALSE];
    END; 


 -- ********************* Frame Pack Module Printing *********************

  PrintFramePackModules: PROC =
    {FramePackModules.EnumerateFramePacks[PrintOneFramePack]};

  PrintOneFramePack: PROC [fpNode: Tree.Index] RETURNS [stop: BOOLEAN] =
    BEGIN
    IF fpNode # Tree.nullIndex THEN 
      BEGIN
      WriteChar['\n];
      WITH tb[fpNode].son[1] SELECT FROM
  	hash => WriteHTI[index];
  	ENDCASE;
      WriteString[": FRAME PACK =\n"L]; 
      WriteString["  BEGIN\n"L];  
      FramePackModules.EnumerateModules[fpNode, PrintOneFramePackModule];
      WriteString["  END;\n"L];
      END;  
    RETURN[FALSE]; 
    END;

  PrintOneFramePackModule: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] =
    BEGIN
    WriteString["  "L];  PrintModuleInstanceName[mti];  WriteString[";\n"L];
    RETURN[FALSE]; 
    END; 

  PrintModuleInstanceName: PROC [module: BcdDefs.MTIndex] =
    BEGIN
    name: BcdDefs.NameRecord;
    firstNode, n: SourceBcd.CTreeIndex;
    
    WriteQualifiedName: PROC [cNode: SourceBcd.CTreeIndex] =
      BEGIN
      IF cNode.Father # SourceBcd.nullCTreeIndex THEN
        {WriteQualifiedName[cNode.Father];  WriteChar['.]};
      WriteName[cNode.Name[$instance]];
      END;

    name ← SourceBcd.bcdBases.mtb[module].name;
    firstNode ← SourceBcd.LookupName[name, instance];
    IF firstNode = SourceBcd.nullCTreeIndex THEN ERROR PackListError;
    IF firstNode.Prev[$instance] = SourceBcd.nullCTreeIndex THEN
      WriteName[name]
    ELSE
      BEGIN  -- name is not unique, so find and print correct qualified name
      FOR n ← firstNode, n.Prev[$instance] UNTIL n = SourceBcd.nullCTreeIndex DO
        index: SourceBcd.BcdTableLoc = n.Index;
        WITH index SELECT FROM
          module => IF mti = module THEN {WriteQualifiedName[n];  RETURN};
          ENDCASE;
        ENDLOOP;
      ERROR PackListError;  -- could not find the module to print out
      END;
    END; 


 -- ************************ Utility Writes ************************ 

  WriteChar: PROC [c: CHARACTER] = INLINE 
    {CharIO.PutChar[gd.packListStream, c]};

  WriteString: PROC [s: LONG STRING] = INLINE 
    {CharIO.PutString[gd.packListStream, s]};

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

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

  WriteName: PROC [name: BcdDefs.NameRecord] =
    BEGIN
    nameSubStr: SubString ← @nameDesc;
    nameDesc: SubStringDescriptor;
    nameDesc ← SubStringDescriptor[base: @SourceBcd.bcdBases.ssb.string, 
      offset: name, length: SourceBcd.bcdBases.ssb.size[name]];
    WriteSubString[nameSubStr];
    END;

  WriteNameFromTable: PROC [n: BcdDefs.Namee] =
    BEGIN 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;
    END;

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

  END.