{$D+,O+,S+,R-,L+}
Unit TPU6AMS;

(*****************)
(**) INTERFACE (**)             USES Dos;
(*****************)

TYPE

  Str2   = String[2]; Str4 = String[4];
  RngB   = 0..65534;
  RngW   = 0..32766;
  AryB   = ARRAY[rngb] OF Byte;
  AryW   = ARRAY[rngw] OF Word;
  SrcNam = String[12];
  LexNam = String[63];

  HdrAry = ARRAY[0..3] OF Char;

  LL  = Word;               { Local Scope Pointers (offsets) }

  LG  = RECORD              { Global Scope Pointers to Other Units }
             UntLL : LL;    { Local to containing unit }
             UntId : LL;    { Local to  external  unit }
        END;

  { The following Record is the Header and Locator for a Unit File } {.CP28}

  UnitPtr = ^UnitHeader;
  UnitHeader = RECORD
	UHEYE : HdrAry;		{ +00 : = 'TPU9'                     }
	UHxxx : HdrAry;		{ +04 : = $00000000                  }
	UHUDH : LL;		{ +08 : to Dictionary Head-This Unit }
	UHIHT : LL;		{ +0A : to Interface Hash Header     }
	UHPMT : LL;		{ +0C : to PROC Map                  }
	UHCMT : LL;		{ +0E : to CSeg Map                  }
	UHTMT : LL;		{ +10 : to DSeg Map-Typed CONST's    }
	UHDMT : LL;		{ +12 : to DSeg Map-GLOBAL Variables }
	UHxxy : LL;		{ +14 : purpose unknown              }
	UHLDU : LL;		{ +16 : to Donor Unit List           }
	UHLSF : LL;		{ +18 : to Source File List          }
	UHDBT : LL;             { +1A : DEBUG Trace Table            }
	UHENC : LL;  		{ +1C : to end non-code part of Unit }
	UHZCS : Word;		{ +1E : CSEG Size-Aggregate          }
	UHZDT : Word;		{ +20 : DSEG Size-Typed CONSTS Only  }
	UHZFA : Word;		{ +22 : Fix-Up Size (Aggregate)      }
	UHZFT : Word;		{ +24 : Fix-Up Size (Typed CONST's)  }
	UHZFV : Word;           { +26 : DSEG Size for Global VARs    }
	UHDHT : LL;		{ +28 : to Global Hash Header        }
        UHSOV : Word;           { +2A : Overlay Controls             }
	UHPad : ARRAY[0..9]
		OF Word;	{ +2C : Reserved for Future Expansion ? }

  END; { UnitHeader }

  { The Records below provide access to the PROC Map }		{.CP12}

	PMapRecPtr  = ^PMapRec;
	PMapRec = RECORD
                ProcWd1,
                ProcWd2 : Word; { function of these words unknown       }
		CSegOfs : Word;	{ offset within CSeg Map; $FFFF if null }
		CSegJmp : Word;	{ offset to entry point;  $FFFF if null }
	END {PMapRec};

	PMapPtr = ^PMapTab;
	PMapTab =  ARRAY[0..1] OF PMapRec; { model of PROC Map }

  { The Records below provide access to the CODE Map }		{.CP12}

	CMapRecPtr = ^CMapRec;
	CMapRec = RECORD
		CSegWd0 : Word;	{ purpose is unknown              }
		CSegCnt : Word;	{ byte count of module code       }
		CSegRel : Word;	{ byte count of module Relo List  }
		CSegTrc : Word;	{ Trace table offset or $FFFF     }
	END; {CMapRec}

	CMapTabPtr = ^CMapTab;
	CMapTab = ARRAY[0..1] OF CMapRec; { model of CSeg Map }

  { The Records below provide access to the CONST DSeg Map }	{.cp12}

	DMapRecPtr = ^DMapRec;
	DMapRec = RECORD
		DSegWd0 : Word;    { purpose is unknown              }
		DSegCnt : Word;    { byte count of data block        }
		DSegRel : Word;    { byte count of data Relo List    }
		DSegOwn : LL;      { To owner scope                  }
	END; {DMapRec}

	DMapTabPtr = ^DMapTab;
	DMapTab = ARRAY[0..1] OF DMapRec;	{ model of DSeg Map }

  { The Record below is one entry in the Fix-Up List }            {.CP13}

	FixUpRecPtr = ^FixUpRec;
	FixUpRec = RECORD
		FixDnr : Byte;	{ Donor Unit Offset }
		FixFlg : Byte;	{ Entry Format Flag }
		FixWd1 : Word;	{ Offset to Map Table  }
		FixWd2 : Word;	{ Effective Address Adjuster  }
		FixOfs : Word;	{ offset to patch point in code/data block }
	END; {FixUpRec}

	FixUpPtr  = ^FixUpList;
	FixUpList = ARRAY[0..1] OF FixUpRec; { model of Fix-Up List }

  { The Record below maps the Dictionary Header in Turbo Units } {.CP08}

	DNamePtr = ^ DNameRec;
	DNameRec = RECORD
		HLink : LL;         { Hash Chain Link; Resolves Collisions }
		DForm : Char;       { Symbol Type; See StubRecord for types}
		DSymb : LexNam;     { Worst-Case Symbol Size (UPPER-CASE)  }
	END; {DNameRec}

  { The Record Below maps the Dictionary Stubs in Turbo Units  } {.CP10}

  DStubPtr = ^ DStubRcd;
  DStubRcd = RECORD
      CASE Char OF

      'P': (                     { --- For Untyped Constants --- }
           sPTD : LG;            { to type descriptor            }
           sPV1 : Word;          { value of constant - LO Word   }
           sPV2 : Word);         { (size varies)     - HI Word   }

      'Y': (                     { ----- For UNIT Entries ------ }  {.CP05}
           sYW1 : Word;          { unknown use; normally zero    }
           sYCS : Word;          { Speculate Signature Word      }
           sYNU : LL;            { to next Unit in List (SUCC)   }
           sYPU : LL);           { to prior Unit in List (PRED)  }

      'O',                       { ---- Label Declaratives ----- }  {.CP05}
      'T',                       { ---- Standard Procedures ---- }
      'U',                       { ---- Standard Functions  ---- }
      'V': (                     { ---- Standard "NEW" F/P  ---- }
           sVxx : Word);         { semantics not precisely known }

      'W': (                     { ------- Standard Ports ------ }  {.CP02}
           sWxx : Byte);         { 0=Byte Array, 1=Word Array    }

      'Q',                       { -------- Named Types -------- }  {.CP03}
      'X': (                     { ----- External Variables ---- }
           sQTD : LG);           { to type descriptor            }

      'S': (                     { ------ User Subprograms ----- }  {.CP20}
            sSTp : BYte;         { 76543210  - Bit encoded       }
                                 { .......1 = FAR Call Model     }
                                 { ......1. = INLINE Declarative }
                                 { .....1.. = INTERRUPT Routine  }
                                 { ....1... = .OBJ module code   }
                                 { ...1.... = METHOD (Any)       }
                                 { .011.... = Constructor METHOD }
                                 { .101.... = Destructor  METHOD }
                                 { 1....... = ASSEMBLER attribute}
            sSxx : Byte;         { function unknown at present   }
            sSPM : Word;         { Code byte count if INLINE,    }
                                 { else, offset to PROC Map      }
            sSPS : LL;           { to containing scope or zero   }
            sSHT : LL;           { to local scope hash table     }
            sSVM : Word);        { VMT Offset-VIRTUAL Method PTR }

            { Notes: "sSVM" is followed immediately by a Type    }
            {        Descriptor ($06).  INLINE Declarative code  }
            {        Bytes then follow (if any).                 }

      'R': (                     { -- Variable, Field, Object  -- } {.CP35}
            sRAM : Byte;         {   allocation method codes:      }
                                 { $00 = Global Variables in DS    }
                                 { $01 = Typed Constants  in DS    }
                                 { $02 = VAR-BP based-Nested Scope }
                                 { $03 = Absolute[Segment:Offset]  }
                                 { $06 = SELF Parameter-ADDR Stack }
                                 { $08 = Allocate in Record/Object }
                                 { $10 = Absolute Equivalence      }
                                 { $22 = VALUE Parameter-BP based  }
                                 { $26 = VAR   Parameter-BP based  }

            sRVF : Longint;      { See VarStub Below               }
            sRTD : LG);          { to Type Descriptor              }

      END;

  VarStubPtr = ^VarStub;
  VarStub    = RECORD
            Case  Byte Of  { sRAM Byte in Type "R" Stub }
            $02,$06,
            $22,$26:     (ROfs : Word;  { allocation offset (BP)  }
                          ROB  : Word); { To Parent Scope/Zero    }

            $00,$01:     (TOfs : Word;  { allocation offset in map}
                          TOB  : LL);   { offset in VAR/CONST Map }

            $03:         (AOfs : Word;  { Absolute Byte Offset    }
                          ASeg : Word); { Absolute Segment Adr    }

            $08:         (Bofs : Word;  { Offset-Record Relative  }
                          RChn : LL);   { To Next Field/Method    }

            $10:         (QLG  : LG);   { to Stub of Allocator    }
  End;

  { The Record below maps a Formal Parameter List Entry }        {.CP08}

  FormalParmRcd = RECORD
	   fPTD : LG;		{ to type descriptor for parameter  }
	   fPAM : Byte;		{ passing model; 2=Value, 6=Address }
     END;

  InlineLst = ARRAY[0..1] OF Word;		{ model of INLINE code }


  { The Record below maps the Type Descriptors in Turbo Units  } {.CP08}

  TypePtr   = ^TypeRecd;
  TypeRecd  = RECORD
       tpTC : Byte;		{ Identifies the Variant Part }
       tpTQ : Byte;		{ Type Qualifier              }
       tpSW : Word;		{ Storage Width in Bytes      }
       tpML : Word;             { Next Method if tpTC=$06     }

       CASE Byte OF                                                 {.CP04}
	$00,			{ For NULL or Un-Typed Variables }
	$0A,			{ For COMP,DOUBLE,EXTENDED,SINGLE }
	$0B : ();		{ -------- For REAL Type -------- }

	$01 : (			{ ------ For ARRAY Types ------- }  {.CP04}
		BaseType : LG;	{ to TypeRecd for item arrayed   }
		BounDesc : LG;	{ to TypeRecd for array bounds   }
              );

	$02 : (			{ ------ For RECORD Types ------ }  {.CP04}
		RecdHash : LL;	{ to Hash Table for Field List   }
		RecdDict : LL;	{ to Field List Dictionary Begin }
              );

	$03 : (			{ ------ For OBJECT Types ------ }  {.CP15}
		ObjtHash : LL;	{ to Fields & Methods Hash Table }
		ObjtDict : LL;	{ to Fields & Methods Dictionary }
		ObjtOwnr : LG;	{ to Parent Object Type Descript }
		ObjtVMTs : Word;{ Size of VMT if Virtual Methods }
		ObjtDMap : Word;{ Data Map Offset of VMT Template}
		ObjtVMTO : Word;{ object instance offset to VMT  }
				{ pointer; $FFFF if object has   }
				{ no Virtual Methods (no VMT)    }
		ObjtName : LL;	{ to Object Dictionary Header    }
                ObjtRes0,       { Usually $FFFF - Role Unknown   }
                ObjtRes1,       { Usually zero  - Role Unknown   }
                ObjtRes2,       { Usually zero  - Role Unknown   }
                ObjtRes3 : Word { Usually zero  - Role Unknown   }
              );

	$04,			{ ----- For FILE except TEXT ----}  {.CP04}
	$05:  (			{ ----- For TEXT file type ----- }
		FileType : LG;	{ to TypeRecd for Base File Type }
              );
	$06:  (			{ ----- For Procedure Types ---- }  {CP05}
		PFRes : LG;	{ to Function Result TD / zero   }
		PNPrm : Word;	{ Formal Parameter Count/ zero   }
                PFPar : ARRAY[1..2] OF FormalParmRcd { model only}
              );
	$07 : (			{ ------- For SET Types -------- } {.CP03}
		SetBase  : LG;	{ to base type descriptor of set }
              );
	$08 : (			{ ----- For POINTER Types ------ } {.CP03}
		PtrBase  : LG;	{ to base type descriptor        }
              );
	$09 : (			{ ------ For STRING Types ------ } {.CP04}
		StrBase  : LG;	{ to SYSTEM.CHAR type descriptor }
		StrBound : LG;	{ to array bounds for string typ }
              );
	$0C,		 { For BYTE,INTEGER,LONGINT,SMALLINT,WORD }{.CP15}
	$0D,			{ ------- For BOOLEAN Type ------ }
	$0E,			{ ------- For CHAR Type --------- }
	$0F : (			{ ---- For Enumerated Types ----- }
		LoBnd : LongInt;{ lower bound of subrange         }
		HiBnd : LongInt;{ upper bound of subrange         }
		Cmpat : LG;	{ to upward compatible Type desc  }
              );

		{ The Enumeration Type Descriptor is immediately  }
		{ followed by a SET Type Descriptor ($07) but we  }
		{ don't know what this achieves.  Its base type   }
		{ LG points to the Enumerated Type Descriptor.    }

       END;  { TypeRecd }


  { The Record below is a model Hash Table }                         {.CP07}

	HashPtr   = ^HashTable;
	HashTable = RECORD
		Bas : Word;                { Base and Max Offset in Slt }
		Slt : ARRAY[0..1] Of LL;   { Slots in Hash Table        }
	END;

  { The Record below is an entry in the Unit Code/Data Donor List } {.CP07}

	UDonorPtr = ^UDonorRec;
	UDonorRec = RECORD
		UDExxx : Word;
		UDEnam : String[8]
	END;

  { The Record below is an entry in the Source File List }            {.CP10}

	SrcFilePtr = ^SrcFileRec;
	SrcFileRec = RECORD
		SrcFlag : Byte;		{ 4=.PAS file, 3=.INC, 5=.OBJ       }
		SrcPad  : Word;		{ no apparent use - always zero ?   }
		SrcTime : Word;		{ File Time Stamp if SrcFlag=3 or 4 }
		SrcDate : Word;		{ File Date Stamp if SrcFlag=3 or 4 }
		SrcName : SrcNam;	{ Varying length FileName.Extn      }
	END;

  { The Record below is an entry in the Trace Table      }          {.CP12}

	TraceRecPtr = ^TraceRec;
	TraceRec    = RECORD
	    TrName : LL;	 { to Directory Entry of Proc/Method  }
	    TrFill : Word;	 { to proc source file                }
	    TrPfx  : Word;	 { bytes of data in front of code     }
	    TrBeg  : Word;	 { Line Number of BEGIN Stmt          }
	    TrLNos : Word;	 { Lines of Code to Execute in TRACE  }
	    TrExec : ARRAY[1..2] { Model Array of bytes that map each }
		     OF Byte;	 { line of code to be traced by DEBUG }
	END;

  BufPtr = ^Buffer;                                             {.CP06}
  Buffer = RECORD               { General Buffer Mapping }
    CASE Boolean OF
      True :( BufByt : AryB);   { Byte Array over Buffer }
      False:( BufWrd : AryW);   { Word Array over Buffer }
    END;

VAR  BufPtrJob : BufPtr;

PROCEDURE InitJobUnit(FilNam:Dos.PathStr);                      {.CP27}
PROCEDURE DropJobUnit;
FUNCTION  PtrAdjust(Arg : Pointer; Adj: Word):Pointer;
FUNCTION  FormLL(Base,Ceil:Pointer):LL;
FUNCTION  HexB(Arg:byte):Str2;
FUNCTION  HexW(Arg:Word):Str4;
FUNCTION  IsSystemUnit(U : UnitPtr): Boolean;
FUNCTION  AddrStub(arg : DNamePtr):DStubPtr;
FUNCTION  AddrHash(U : UnitPtr; Hash : LL): HashPtr;
FUNCTION  AddrDict(U : UnitPtr; Hash : LL): DNamePtr;
FUNCTION  AddrType(U : UnitPtr; TypeLG : LG):TypePtr;
FUNCTION  AddrProcType(S : DStubPtr):TypePtr;
FUNCTION  AddrNxtSrc(U : UnitPtr; Arg : SrcFilePtr):SrcFilePtr;
FUNCTION  AddrSrcTabOff(U : UnitPtr; Offset : Word):SrcFilePtr;
FUNCTION  CountPMapSlots(U : UnitPtr):Integer;
FUNCTION  AddrPMapTab(U : UnitPtr):PMapPtr;
FUNCTION  CountCMapSlots(U : UnitPtr):Integer;
FUNCTION  AddrCMapTab(U : UnitPtr):CMapTabPtr;
FUNCTION  CountDMapSlots(U : UnitPtr):Integer;
FUNCTION  AddrDMapTab(U : UnitPtr):DMapTabPtr;
FUNCTION  AddrTraceTab(U : UnitPtr):TraceRecPtr;
FUNCTION  GetTrExecSize(T : TraceRecPtr):Integer;
FUNCTION  AddrNxtTrace(U : UnitPtr; T : TraceRecPtr):TraceRecPtr;
FUNCTION  AddrFixUps(U : UnitPtr):FixUpPtr;
FUNCTION  AddrLGUnit(U : UnitPtr; TypeLG : LG):DNamePtr;
FUNCTION  Public(Arg : Char) : Char;
FUNCTION  PtrNormal(P : Pointer) : Pointer;
(**********************)                                        {.CP24}
(**) IMPLEMENTATION (**)
(**********************)

TYPE

  Fstats = RECORD
	Size : Longint;
	Path : Dos.PathStr;
  END;

CONST

  TurboId6  : HdrAry = 'TPU9';
  NullOfs   : Word   = $FFFF;

VAR

  TPFile    : File;
  SizRefBfr,
  SizJobBfr : Word;
  BufPtrRef : BufPtr;

  JobPath   : Dos.PathStr;

  { Function Below Converts PRIVATE Names to PUBLIC }           {.CP04}

FUNCTION Public(Arg : Char) : Char;
BEGIN Public := Chr(Ord(Arg) AND $7F) END;

  { Function Below Converts POINTER to Normalized Form }        {.CP18}

FUNCTION  PtrNormal(P : Pointer) : Pointer;
Var I, J : Word;
Begin
   I := Seg(P^); J := Ofs(P^);
   ASM
      MOV   AX,J        { get OFFSET }
      ADD   AX,7        { round up to QWORD }
      MOV   BX,00008h   { set AND mask for offset }
      AND   BX,AX       { normalize new offset }
      MOV   J,BX        { save normalized offset }
      MOV   CX,4        { load shift width  }
      SHR   AX,CL       { drop offset digit }
      ADD   I,AX        { normalize segment }
   End;
   PtrNormal := Ptr(I,J)
End;

  { Procedure Below Traps Pointer Violations }			{.CP10}

PROCEDURE CheckPtrs(U,V:Pointer);
BEGIN
	IF (U = Nil) OR (V = Nil) OR (Seg(U^) <> Seg(V^)) THEN
	BEGIN
		WriteLn('Pointer Violation in CheckPtrs');
		Halt(1)
	END
END; {CheckPtrs}

  { Function Below Computes an LL from two Pointers }           {.CP09}

FUNCTION  FormLL(Base,Ceil:Pointer):LL;
BEGIN
	CheckPtrs(Base,Ceil);
	IF Ofs(Base^) > Ofs(Ceil^)
		THEN FormLL := LL(Ofs(Base^)-Ofs(Ceil^))
		ELSE FormLL := LL(Ofs(Ceil^)-Ofs(Base^));
END;

  { Function Below Adjusts Pointer Values by Offsets }           {.CP04}

FUNCTION  PtrAdjust(Arg : Pointer; Adj: Word):Pointer;
BEGIN     PtrAdjust := Ptr(Seg(Arg^),Ofs(Arg^) + Adj)     END;

  { Function Below Checks to See if Unit Name is "SYSTEM" }

FUNCTION  IsSystemUnit(U : UnitPtr): Boolean;
BEGIN
   IsSystemUnit := DNamePtr(Ptr(Seg(U^),Ofs(U^)+U^.UHUDH))^.DSymb = 'SYSTEM'
END;

  { Function Below Finds The Stub Belonging to a Dictionary Header } {.CP05}

FUNCTION  AddrStub(Arg : DNamePtr):DStubPtr;
CONST PrefixSize = SizeOf(LL)+SizeOf(Char) + 1;
BEGIN  AddrStub := PtrAdjust(Arg,PrefixSize + Ord(Arg^.DSymb[0]))  END;

  { Function Below Gets Pointer to Hash Table }                  {.CP04}

FUNCTION  AddrHash(U : UnitPtr; Hash : LL): HashPtr;
BEGIN   AddrHash := HashPtr(PtrAdjust(U,Hash))  END;

  { Function Below Gets Pointer to Dictionary Entry using LL }   {.CP04}

FUNCTION  AddrDict(U : UnitPtr; Hash : LL): DNamePtr;
BEGIN AddrDict := DNamePtr(PtrAdjust(U,Hash)) END;

  { Function Below Gets Pointer to Type Descriptor if Local to Unit } {.CP12}

FUNCTION  AddrType(U : UnitPtr; TypeLG : LG):TypePtr;
VAR D:DNamePtr; S:DStubPtr; R:LL;
BEGIN
	D := AddrDict(U,U^.UHUDH);      {point to our unit DE}
	S := AddrStub(D);               {point to its stub   }
	R := FormLL(U,S);               {get offset to stub  }
	IF R = TypeLG.UntId             {if offset matches   }
	THEN AddrType := TypePtr(PtrAdjust(U,TypeLG.UntLL))
	ELSE AddrType := Nil
END;

  { Function Below Gets Pointer to Unit Descriptor for Type via LG } {.CP21}

FUNCTION  AddrLGUnit(U : UnitPtr; TypeLG : LG):DNamePtr;
VAR D:DNamePtr; S:DStubPtr; R:LL;
BEGIN
	D := AddrDict(U,U^.UHUDH);      {point to our unit hdr}
	S := AddrStub(D);               {point to our stub    }
	R := FormLL(U,S);               {get offset to stub   }
	IF (R <> 0) THEN
	IF (TypeLG.UntID <> R) THEN     {if offsets don't match }
	REPEAT
	   D := AddrDict(U,S^.sYNU);            {chain to next DE}
	   IF D^.DForm <> 'Y' THEN R := 0 ELSE  {if next is unit }
	   BEGIN
	     S := AddrStub(D);                  {its stub address}
	     R := FormLL(U,S);                  {and stub offset }
	   END;
	UNTIL (R = TypeLG.UntID) OR (R = 0);    {match of end list  }
	IF R <> 0 THEN AddrLGUnit := D          {we had a match     }
	          ELSE AddrLGUnit := Nil;       {we couldn't find it}
END;

  { Function Below Gets Pointer to Procedure Stub Type Descriptor }{.CP04}

FUNCTION  AddrProcType(S : DStubPtr):TypePtr;
BEGIN AddrProcType := TypePtr(PtrAdjust(@S^.sSVM,SizeOf(S^.sSVM))) END;

  { Function Below Gets Pointer to Next Entry in Source File List } {.CP21}

FUNCTION  AddrNxtSrc(U : UnitPtr; Arg : SrcFilePtr):SrcFilePtr;
VAR J : LL;  S : SrcFilePtr;
BEGIN
	J := 0;
	IF Arg = Nil THEN AddrNxtSrc := Nil ELSE
	BEGIN
	   J := FormLL(U,Arg);
	   IF J < U^.UHLSF
	   THEN AddrNxtSrc := Nil ELSE
	   IF NOT (J < U^.UHDBT)
	   THEN AddrNxtSrc := Nil ELSE
	   BEGIN
	      S := SrcFilePtr(PtrAdjust(Arg,8 + Ord(Arg^.SrcName[0])));
	      IF FormLL(U,S) < U^.UHDBT
	      THEN AddrNxtSrc := S
	      ELSE AddrNxtSrc := Nil
	   END
	END
END;

  { Function Below Gets Pointer to Source File List Entry at Offset }{.CP09}

FUNCTION  AddrSrcTabOff(U : UnitPtr; Offset : Word):SrcFilePtr;
BEGIN
	WITH U^ DO
	IF (UHLSF+Offset) < UHDBT
	THEN AddrSrcTabOff := SrcFilePtr(PtrAdjust(U,UHLSF+Offset))
	ELSE AddrSrcTabOff := Nil
END;

  { Function Counts Number of Slots in PROC Map Table }            {.CP06}

FUNCTION  CountPMapSlots(U : UnitPtr):Integer;
BEGIN
	CountPMapSlots := (U^.UHCMT-U^.UHPMT) DIV SizeOf(PMapRec);
END;

  { Function Gets Address of PROC Map Table }                      {.CP08}

FUNCTION  AddrPMapTab(U : UnitPtr):PMapPtr;
BEGIN
	IF CountPMapSlots(U) > 0
	THEN AddrPMapTab := PMapPtr(PtrAdjust(U,U^.UHPMT))
	ELSE AddrPMapTab := Nil
END;

  { Function Counts Number of Slots in CSeg Map Table }         {.CP06}

FUNCTION  CountCMapSlots(U : UnitPtr):Integer;
BEGIN
	WITH U^ DO CountCMapSlots := (UHTMT-UHCMT) DIV SizeOf(CMapRec);
END;

  { Function Gets Address of CSeg Map Table }                   {.CP08}

FUNCTION  AddrCMapTab(U : UnitPtr):CMapTabPtr;
BEGIN
	IF CountCmapSlots(U) > 0
	THEN AddrCMapTab := CMapTabPtr(PtrAdjust(U,U^.UHCMT))
	ELSE AddrCMapTab := Nil
END;

  { Function Counts Number of DSeg Map Slots }                  {.CP06}

FUNCTION  CountDMapSlots(U : UnitPtr):Integer;
BEGIN
	WITH U^ DO CountDMapSlots := (UHDMT - UHTMT) DIV SizeOf(DMapRec)
END;

  { Function Gets Address of DSeg Map Table }                   {.CP08}

FUNCTION  AddrDMapTab(U : UnitPtr):DMapTabPtr;
BEGIN
	IF CountDMapSlots(U) > 0
	THEN AddrDMapTab := DMapTabPtr(PtrAdjust(U,U^.UHTMT))
	ELSE AddrDMapTab := Nil
END;

  { Function Below Gets Pointer to 1st Trace Table Entry or Nil }  {.CP08}

FUNCTION  AddrTraceTab(U : UnitPtr):TraceRecPtr;
BEGIN
	IF U^.UHDBT = U^.UHENC
	THEN AddrTraceTab := Nil
	ELSE AddrTraceTab := TraceRecPtr(PtrAdjust(U,U^.UHDBT))
END; {AddrTraceTab}

   { Function Below Gets Byte Count in TrExec Array }      {.CP20}

FUNCTION GetTrExecSize(T : TraceRecPtr):Integer;
VAR i,k : Integer;
BEGIN
   IF T = Nil THEN GetTrExecSize := 0 ELSE
   BEGIN
      k := T^.TrLNos;                   {number of lines in array}
      i := 1;                           {prime scan line number  }
      WHILE i <= k DO BEGIN             {still have lines to test}
         IF T^.TrExec[i] = $80 THEN     {if "escape byte" present}
	 BEGIN
	   Inc(k);                      {bump array limit        }
	   Inc(i)                       {bump to byte count slot }
	 END;
	 Inc(i)                         {check next slot         }
      END;
      GetTrExecSize := k;               {final byte count        }
   END;
END;

  { Function Below Gets Pointer to next Trace Table Entry or Nil }  {.CP14}

FUNCTION  AddrNxtTrace(U : UnitPtr; T : TraceRecPtr):TraceRecPtr;
VAR k : Integer;
BEGIN
	IF T = Nil THEN AddrNxtTrace := Nil ELSE
	BEGIN
		k := GetTrExecSize(T);
		T := TraceRecPtr(PtrAdjust(@T^.TrExec[1],LL(k)));
		IF FormLL(U,T) >= U^.UHENC
			THEN AddrNxtTrace := Nil
			ELSE AddrNxtTrace := T
	END
END; {AddrNxtTrace}

  { Function Below Gets Pointer to 1st Fixup Table Entry or Nil }  {.CP13}

FUNCTION  AddrFixUps(U : UnitPtr):FixUpPtr;
VAR j : Word;
BEGIN
	IF U^.UHZFA = 0 THEN AddrFixUps := Nil ELSE
	WITH U^ DO BEGIN
		j := (UHENC  + $F) AND $FFF0;
		j := (UHZCS  + $F) AND $FFF0 + j;
		j := (UHZDT  + $F) AND $FFF0 + j;
		AddrFixUps := Ptr(Seg(U^),Ofs(U^) + j)
	END
END; {AddrFixUps}

  { Function Below Converts a byte to Printable Hex }               {.CP05}

FUNCTION HexB(arg:byte): Str2;
CONST HexTab : ARRAY[0..15] OF Char = '0123456789ABCDEF';
BEGIN HexB := HexTab[arg SHR 4] + HexTab[arg AND $F] END;

  { Function Below Converts a Word to Printable Hex in Dump Mode }  {.CP04}

FUNCTION HexW(arg:Word): Str4;
BEGIN HexW := HexB(HI(arg)) + HexB(LO(arg)) END;

PROCEDURE FindFile(FName : String; VAR Finding : FStats);        {.CP14}
CONST AttrMask = Dos.Archive + Dos.ReadOnly + Dos.SysFile;
VAR   S : Dos.SearchRec; P : Dos.DirStr; N : Dos.NameStr; X : Dos.ExtStr;
BEGIN
	Finding.Size := -1;
	FSplit(FName,P,N,X);
	IF (X = '') OR (X = '.') THEN X := '.TPU';
	Finding.Path := FSearch(N + X,GetEnv('PATH'));
	IF Finding.Path <> '' THEN
	BEGIN
		FindFirst(Finding.Path,AttrMask,S);
		IF DosError = 0 THEN Finding.Size := S.Size
	END
END;

PROCEDURE OpenUnit(Path : String);                               {.CP07}
BEGIN
   {I-}
        Assign(TPFile , Path);
        Reset(TPFile,1);
   {$I+}
END;

PROCEDURE CloseUnit;                                             {.CP05}
BEGIN
	{$I-} Close(TPFile); {$I+}
	IF IOResult <> 0 THEN;
END;

PROCEDURE InitJobUnit(FilNam:Dos.PathStr);                      {.CP14}
VAR W : FStats;
BEGIN
	DropJobUnit;
	FindFile(FilNam,W);
	IF (W.Size > 0) AND (W.Size < 65536) THEN
	BEGIN
		SizJobBfr := W.Size;
		OpenUnit(W.Path);
		GetMem(BufPtrJob,SizJobBfr);
		BlockRead(TPFile,BufPtrJob^.BufByt,SizJobBfr);
		CloseUnit;
	END
END;

PROCEDURE DropJobUnit;                                         {.CP11}
BEGIN
	IF BufPtrJob <> Nil THEN
	BEGIN
		FreeMem(BufPtrJob,SizJobBfr);
		CloseUnit;
	END;
	BufPtrJob := Nil;
	SizJobBfr := 0;
END;

BEGIN    { UNIT INITIALIZATION CODE }                        {.CP10}

	SizRefBfr := 0;
	SizJobBfr := 0;
	JobPath   := '';
	BufPtrRef := Nil;
	BufPtrJob := Nil;

END.
