home *** CD-ROM | disk | FTP | other *** search
- {$R-,E-,N-,S+}
- Unit TPU6UTL;
-
- { This Unit provides the tools needed for high-level analysis }
- { of desired units by the main program (TPU6). It is object }
- { oriented in its implementation but not in its interface. }
- { The intended user of this unit has relatively simple needs }
- { and no additional capabilities are provided. In particular }
- { the details of implementation including data structures are }
- { hidden from any potential user. The object methodology is }
- { not very spiritual. Neither inheritance nor virtual method }
- { techniques are employed, but static objects are utilized to }
- { assist with data management on the heap providing a highly }
- { structured environment for implementation. }
-
- (*****************)
- (**) INTERFACE (**) Uses TPU6EQU, TPU6AMS, TPU6RPT, Dos;
- (*****************)
-
- { -------------------------------------------------------- } {.CP04}
- { PurgeAllUnits - Removes all Units and Analyses from Heap }
-
- Procedure PurgeAllUnits;
-
- { --------------------------------------------------------------- }{.CP05}
- { AnalyzeUnit - Loads and analyzes a Unit; references to Units }
- { it USES are resolved to clarify LG references }
-
- Function AnalyzeUnit(Name: _UnitName; Path: String): UnitPtr;
-
- { --------------------------------------------------------------- }{.CP13}
- { ResolveLG - Checks all Directly referenced Units to locate }
- { the Unit and the Dictionary Entry for the owner }
- { of the Descriptor referenced by an LG provided }
- { AnalyzeUnit has been called before-hand }
-
- Type
- RespLG = Record { Returned by ResolveLG }
- UPtr : UnitPtr; { Pointer to Named Unit }
- Ownr : LL; { LL to Owner of LG'd Item }
- End;
-
- Procedure ResolveLG(N: _UnitName; L : LG; VAR R: RespLG);
-
- { ---------------------------------------------------------- } {.CP23}
- { FetchSurveyRec - is called to fetch the next SurveyRec }
- { to support formatted Dictionary printing }
- { of the primary Unit }
-
- Type CoverId = (cvName, { Dictionary Entry Headers }
- cvHash, { Hash Tables }
- cvType, { Type Descriptors }
- cvINLN, { INLINE Code Bytes }
- cvNULL); { terminating status }
-
- SurveyRecPtr = ^ SurveyRec; { Output of Survey }
-
- SurveyRec = RECORD
- LocLL : LL; { LL to location of data structure }
- LocOwn : LL; { LL to Dictionary Header of Owner or 0 }
- LocTyp : CoverId; { Class of Structure (see above) }
- LocNxt : LL; { LL to location of following structure }
- LocLvl : Word; { Nesting Level of entry }
- End;
-
- Procedure FetchSurveyRec (VAR S : SurveyRec); { Gets Dictionary Survey }
- { Results Sequentially }
-
- { ---------------------------------------------------------------- } {.CP53}
- { SortProcRefs - is called to sort the reference information for }
- { PROC Maps into either CSEG or PROC map order to }
- { print. BOTH sequences are used by TPU6. Only a }
- { Unit has such references constructed for it. }
- { }
- { FetchMapRef - is called to fetch a MapRefRec (see below) using }
- { the map offset. Only the primary Unit has such }
- { references constructed for it. }
-
- Type
- MapFlags = (mfNULL, { Undefined / Unused Entry }
- mfINTF, { INTERFACE CONST/VAR Map Entry }
- mfIMPL, { IMPLEMENTATION CONST/VAR Map }
- mfNEST, { NESTED Scope Typed CONST DSeg }
- mfXTRN, { EXTERNAL CONST/VAR DSeg }
- mfTVMT, { VMT Template in CONST Map }
- mfPROC, { PROC Map Entry }
- mfPRUI, { PROC Map Entry - Unit Init }
- mfCSEG); { CSEG Map Entry }
-
- MapClass = (rPROC, { PROC Map }
- rCSEG, { CSeg Map }
- rVARS, { VARS Map - Global VAR DSeg Map }
- rCONS); { CONS Map - Typed Constants Map }
-
- MapRefRecPtr = ^ MapRefRec; { Output of VAR/CONST Map Survey }
- MapRefRec = RECORD
- MapTyp : MapFlags; { Defining Scope Category (see above) }
- MapOfs : Word; { Offset within Map Table }
- MapOwn : LL; { DNAME of Parent Scope / PROC }
- MapSrc : LL; { Offset in Source File Table }
- MapLod : LL; { Load Point for CODE/CONST Segment }
- MapSiz : Word; { Size of Segment / PROC (Bytes) }
-
- CASE MapFlags OF
- mfCSEG: ( {--CSEG/CONST Map Table Only--}
- MapFxI : LL; { Segment Fix-Up (Initial) }
- MapFxJ : LL; { Segment Fix-Up (Final) }
- );
- mfPROC: ( {-----PROC Map Table Only-----}
- MapEPT : LL; { Entry Point for PROC }
- MapCSM : LL; { Offset in CSEG Map for PROC }
- );
- END;
-
- SortMode = (CSegOrder, { Sort Proc Map into CSeg Order }
- PMapOrder); { Sort Proc Map into Proc Order }
-
- Procedure SortProcRefs (Mode : SortMode); { PROC Map Ref Sorts }
-
- Procedure FetchMapRef (VAR S : MapRefRec; { Gets map references }
- C : MapClass; { for the primary unit }
- Offset: Word);
-
- (**********************) {.PA}
- (**) IMPLEMENTATION (**)
- (**********************)
-
- Type
- UnitMode = (Entire,Partial);
- TUnitPtr = ^ TUnit;
- RMapPtr = ^ RMap;
- MapTabPtr = ^ MapTab;
- CvrTabPtr = ^ CvrTab;
- CvrRecPtr = ^ CvrRec;
-
- CvrRec = RECORD
- LocLL : LL; { LL to location of data structure }
- LocOwn : LL; { LL to Dictionary Header of Owner or 0 }
- LocTyp : CoverId; { Type of Structure }
- LocLvl : Word; { Entry Nesting Level in Dictionary }
- END;
-
- CvrTab = ARRAY[1..2] OF CvrRec; { Model of Stack/Queue }
- MapTab = ARRAY[0..4] OF MapRefRec; { Model of Cross-Refs }
-
- RMapVec = Array[MapClass] of RMapPtr;
-
- { ----------------------------------------------------- } {.CP38}
- { The TUnit Object is used to organize all information }
- { known about a Unit. It functions as an index node to }
- { allow reasonably fast access to a Unit by either name }
- { or by address. It provides links RMap objects which }
- { anchor "map" analyses. It contains the controls that }
- { manage the dictionary "cover" built for each Unit. }
- { ----------------------------------------------------- }
-
- TUnit = Object
- Link : TUnitPtr; { To Next TUnit in List }
- UImg : UnitPtr; { To Unit Image on Heap }
- USiz : Word; { Allocated Image Size }
- Name : _UnitName; { Name for Fast Search }
- CvrRMaps : RMapVec; { To Map Analyses }
- CvrStkPtr : CvrTabPtr; { To Cover Stack }
- CvrQuePtr : CvrTabPtr; { To Completed Survey }
- CvrSize: LongInt; { Allocation Size Bytes }
- CvrLimit, { Stack/Queue Maxima }
- CvrStkTop, { Cover Stack Top }
- CvrQueTail, { Cover Queue Tail }
- CvrStkBot, { Cover Stack Bottom }
- CvrStkMax, { Cover Stack Ceiling }
- CvrQueHead, { Cover Queue Head }
- CvrQueMax : Word; { Cover Queue Ceiling }
- Destructor Done;
- Constructor Init(Id: _UnitName; Locn: UnitPtr; Size: Word);
- Procedure DisposeStack;
- Procedure DisposeQueue;
- Procedure PackQueue;
- Procedure CalcCovers;
- Procedure IndexMaps;
- FUNCTION QueuePos(Locn : LL) : Word;
- PROCEDURE EnQueue(Arg : CvrRec);
- FUNCTION Queued(Key : LL) : Boolean;
- PROCEDURE Push(ArgLoc,ArgOwn : LL; ArgTyp : CoverId; ArgLvl:Word);
- PROCEDURE Pop(VAR Arg : CvrRec);
- End; { TUnit }
-
- { ----------------------------------------------------- } {.CP17}
- { The RMap Object is used to organize the information }
- { pertaining to Unit Map references. One such object }
- { is spawned for each Map type (CSeg,PROC,DSeg,CONST) }
- { and this object stores allocator information about }
- { the vector in which the references are stored. }
- { ----------------------------------------------------- }
-
- RMap = Object
- RMapTabPtr : MapTabPtr; { To Map References }
- RMapTabSiz : Word; { Reference Counter }
- Destructor Done;
- Constructor Init(Width : Word);
- Procedure SortPmap(Mode : SortMode);
- Procedure FetchRef(VAR S : MapRefRec; Offset : Word);
- Procedure StoreRef( S : MapRefRec; Offset : Word);
- End;
-
- Const RecLen = SizeOf(MapRefRec); MapLen = SizeOf(DMapRec);
- LstRoot : TUnitPtr = Nil; LstLocus : TUnitPtr = Nil;
- NullMap : MapRefRec = (MapTyp: mfNULL; MapOfs: 0;
- MapOwn: $FFFF; MapSrc: 0;
- MapLod: 0; MapSiz: 0;
- MapEPT: 0; MapCSM: 0);
-
- VAR CvrWork : CvrRec;
-
- { Begin Methods for R M a p } {.CP18}
-
- Constructor RMap.Init(Width : Word);
- Var I : Word; S : MapRefRec;
- Begin
- RMapTabPtr := Nil; RMapTabSiz := Width DIV SizeOf(DMapRec);
- IF RMapTabSiz > 0 Then
- Begin
- GetMem(RMapTabPtr,RMapTabSiz * SizeOf(MapRefRec));
- S := NullMap;
- If RMapTabPtr = Nil Then RMapTabSiz := 0
- Else
- For I := 0 To RMapTabSiz-1 Do Begin
- RMapTabPtr^[i] := S;
- Inc(S.MapOfs,SizeOf(DMapRec));
- End;
- End;
- End;
-
- Destructor RMap.Done; {.CP05}
- Begin
- IF RMapTabSiz > 0 Then FreeMem(RMapTabPtr,RMapTabSiz * RecLen);
- RMapTabPtr := Nil; RMapTabSiz := 0;
- End;
-
- Procedure RMap.SortPmap(Mode: SortMode); {.CP28}
- Var Rmt: MapTabPtr; I, J, K : Word; W: MapRefRec;
- Begin
- Rmt := RMapTabPtr; I := 0;
- If Rmt <> Nil Then
- Repeat { Slow but simple sort }
- J := I + 1; K := I;
- While J < RMapTabSiz Do Begin
- Case Mode Of
- CSegOrder:
- If Rmt^[J].MapCSM < Rmt^[K].MapCSM
- Then K := J Else
- If Rmt^[J].MapCSM = Rmt^[K].MapCSM
- Then If Rmt^[J].MapEPT < Rmt^[K].MapEPT
- Then K := J;
-
- PMapOrder:
- If Rmt^[J].MapOfs < Rmt^[K].MapOfs Then K := J;
- End; {Case}
- Inc(J);
- End; {While}
- If K <> I Then { We need to do a swap }
- Begin
- W := Rmt^[I]; Rmt^[I] := Rmt^[K]; Rmt^[K] := W
- End;
- Inc(I);
- Until I >= RMapTabSiz;
- End; {SortPMap}
-
- Procedure RMap.FetchRef(VAR S : MapRefRec; Offset : Word); {.CP10}
- Var I : Word;
- Begin
- If (Offset MOD MapLen) = 0
- Then I := Offset Div MapLen
- Else I := RMapTabSiz;
- If NOT (I < RMapTabSiz)
- Then S := NullMap
- Else S := RMapTabPtr^[I];
- End;
-
- Procedure RMap.StoreRef(S : MapRefRec; Offset : Word); {.CP09}
- Var I : Word;
- Begin
- If (Offset MOD MapLen) = 0
- Then I := Offset Div MapLen
- Else I := RMapTabSiz;
- If (I < RMapTabSiz)
- Then RMapTabPtr^[I] := S
- End;
-
- { Begin Methods For T U n i t } {.CP18}
-
- Constructor TUnit.Init( Id: _UnitName;
- Locn: UnitPtr;
- Size: Word);
- Begin
- Link := Nil; UImg := Locn;
- USiz := Size; Name := Id;
- CvrRMaps[rPROC] := Nil; CvrRMaps[rCSEG] := Nil;
- CvrRMaps[rVARS] := Nil; CvrRMaps[rCONS] := Nil;
- CvrStkTop := 0; CvrStkBot := 0; CvrStkMax := 0;
- CvrQueTail := 0; CvrQueHead := 0; CvrQueMax := 0;
- CvrStkPtr := Nil; CvrQuePtr := Nil;
- CvrSize := (Locn^.UHPMT-Locn^.UHIHT) + SizeOf(CvrRec) - 1;
- CvrSize := CvrSize-(CvrSize MOD SizeOf(CvrRec));
- CvrLimit:= CvrSize DIV SizeOf(CvrRec);
- GetMem(CvrQuePtr,CvrSize);
- If CvrQuePtr = Nil Then Fail;
- GetMem(CvrStkPtr,CvrSize);
- If CvrStkPtr = Nil Then Fail;
- End; {TUnit.Init}
-
- Procedure TUnit.DisposeStack; {.CP05}
- Begin
- If CvrStkPtr <> Nil Then FreeMem(CvrStkPtr,CvrSize);
- CvrStkPtr := Nil
- End;
-
- Procedure TUnit.DisposeQueue; {.CP05}
- Begin
- If CvrQuePtr <> Nil Then FreeMem(CvrQuePtr,CvrSize);
- CvrQuePtr := Nil
- End;
-
- Procedure TUnit.PackQueue; { Releases un-used part of queue } {.CP15}
- Var T, K : Word; P : Pointer;
- Begin
- If CvrQuePtr <> Nil Then
- Begin
- T := CvrQueTail * SizeOf(CvrRec);
- If T < CvrSize Then
- Begin
- K := (CvrSize - T) AND $FFF8;
- P := PtrNormal(@CvrQuePtr^[CvrQueTail+1]);
- FreeMem(P,K); { VER60 Requires P be Normalized }
- CvrSize := CvrSize - K;
- End;
- End;
- End; {TUnit.PackQueue}
-
- Destructor TUnit.Done; {.CP09}
- Begin
- DisposeStack; DisposeQueue;
- If CvrRMaps[rPROC] <> Nil Then CvrRMaps[rPROC]^.Done;
- If CvrRMaps[rCSEG] <> Nil Then CvrRMaps[rCSEG]^.Done;
- If CvrRMaps[rVARS] <> Nil Then CvrRMaps[rVARS]^.Done;
- If CvrRMaps[rCONS] <> Nil Then CvrRMaps[rCONS]^.Done;
- If UImg <> Nil Then FreeMem(UImg,USiz); UImg := Nil; USiz := 0;
- End;
-
- FUNCTION TUnit.QueuePos(Locn : LL):Word; {.CP16}
- VAR Lo, Mid, Hi : Word;
- BEGIN
- IF CvrQueTail < 1 THEN QueuePos := 1 ELSE
- BEGIN
- Lo := 1; Hi := CvrQueTail;
- REPEAT
- ASM
- XOR BX,BX { make a Zero }
- MOV AX,Lo { fetch Lo }
- ADD AX,Hi { Add Hi }
- RCR BH,1 { save carry }
- SHR AX,1 { divide sum by 2 }
- OR AH,BH { restore carry }
- MOV Mid,AX { save (Lo+Hi) DIV 2 }
- End;
- IF Locn > CvrQuePtr^[Mid].LocLL
- THEN Lo := Mid + 1
- ELSE Hi := Mid - 1
- UNTIL (CvrQuePtr^[Mid].LocLL=Locn) OR (Lo > Hi);
- IF Locn > CvrQuePtr^[Mid].LocLL THEN Inc(Mid);
- QueuePos := Mid;
- END; {WITH}
- END; {QueuePos}
-
- PROCEDURE TUnit.EnQueue(Arg : CvrRec); {.CP40}
- VAR I,J,K,L, Key : LL;
- BEGIN
- If CvrQuePtr <> Nil Then
- If CvrQueTail < CvrLimit Then
- Begin
- Key := QueuePos(Arg.LocLL);
- IF Arg.LocLL < UImg^.UHPMT THEN
- IF Key > CvrQueTail THEN
- BEGIN
- Inc(CvrQueTail);
- CvrQuePtr^[CvrQueTail] := Arg
- END ELSE
- IF Arg.LocLL <> CvrQuePtr^[Key].LocLL THEN { Raise higher entries to }
- BEGIN { make room for insertion }
- Inc(CvrQueTail);
- I := Seg(CvrQuePtr^[CvrQueTail]); { Segment of Tail Entry }
- J := Ofs(CvrQuePtr^[CvrQueTail]); { Offset of Tail Entry }
- K := Ofs(CvrQuePtr^[Key]); { Offset to insert point }
- L := SizeOf(CvrRec); { Size of Cover Record }
- ASM { ASM used for speed only - can be done with FOR Loop }
- PUSH DS { Save DS for Turbo }
- MOV BX,J { Ofs(CvrQuePtr^[CvrQueTail]) }
- MOV CX,BX { Copy To CX }
- DEC BX { Back Down 1 Byte }
- MOV SI,BX { Ofs(CvrQuePtr^[CvrQueTail])-1 }
- MOV AX,L { SizeOf(CvrRec) }
- MOV DI,BX { Ofs(CvrQuePtr^[CvrQueTail])-1 }
- ADD DI,AX { +SizeOf(CvrRec) }
- SUB CX,K { Ofs(CvrQuePtr^[CvrQueTail])-Ofs(CvrQuePtr^[Key]) }
- MOV AX,I { Seg(CvrQuePtr^[CvrQueTail]) }
- MOV ES,AX { Set Target Segment }
- MOV DS,AX { Set Source Segment }
- STD { Set Direction Right-To-Left }
- REPNZ MOVSB { Raise the queue }
- POP DS { Restore DS for Turbo }
- END; { Replacement Ends }
- CvrQuePtr^[Key] := Arg
- END;
- WITH CvrQuePtr^[Key] DO
- IF LocOwn = 0 THEN LocOwn := Arg.LocOwn;
- IF CvrQueTail > CvrQueMax THEN CvrQueMax := CvrQueTail;
- End;
- END; {EnQueue}
-
- PROCEDURE TUnit.Push( ArgLoc, ArgOwn : LL; {.CP13}
- ArgTyp : CoverId; ArgLvl : Word);
- VAR Arg : CvrRec;
- BEGIN
- Arg.LocLL := ArgLoc; Arg.LocOwn := ArgOwn;
- Arg.LocTyp := ArgTyp; Arg.LocLvl := ArgLvl;
- If CvrStkPtr <> Nil Then
- If CvrStkTop < CvrLimit Then
- BEGIN
- Inc(CvrStkTop);
- IF CvrStkTop > CvrStkMax
- THEN CvrStkMax := CvrStkTop;
- CvrStkPtr^[CvrStkTop] := Arg
- END
- END; {Push}
-
- PROCEDURE TUnit.Pop(VAR Arg : CvrRec); {.CP05}
- BEGIN
- If CvrStkPtr <> Nil Then
- If CvrStkTop > 0 Then
- Begin
- Arg := CvrStkPtr^[CvrStkTop];
- Dec(CvrStkTop);
- End;
- END; {Pop}
-
- FUNCTION TUnit.Queued(Key : LL):Boolean; {.CP12}
- VAR Loc : Word;
- BEGIN
- Queued := False;
- If CvrQuePtr <> Nil Then
- If CvrQueTail > 0 Then
- Begin
- Loc := QueuePos(Key);
- IF Loc <= CvrQueTail
- THEN Queued := Key = CvrQuePtr^[Loc].LocLL
- End;
- END; {Queued}
-
- Procedure TUnit.CalcCovers; {.CP03}
-
- PROCEDURE CoverWrapUp;
-
- PROCEDURE CoverWrapPost(x,s:LL); {.CP09}
- VAR J : LL;
- BEGIN
- j := QueuePos(s);
- If CvrQuePtr <> Nil Then
- WITH CvrQuePtr^[j] DO
- IF LocLL = s THEN
- IF (LocOwn > x) OR (LocOwn = 0)
- THEN LocOwn := x;
- END; {CoverWrapPost}
-
- PROCEDURE CoverWrapType(x : LL); {.CP27}
- VAR D : DNamePtr; S : DStubPtr; T : TypePtr; i,j,k : LL;
- RP : VarStubPtr; DF : Char;
- BEGIN
- D := AddrDict(UImg,x); { Q entry }
- S := AddrStub(D); { its stub }
- RP := @S^.sRVF;
- T := AddrType(UImg,S^.sQTD);
- IF T <> Nil THEN { TD in this unit }
- BEGIN
- DF := Public(D^.DForm);
- CoverWrapPost(x,S^.sQTD.UntLL);
- IF (T^.tpTC = 2) OR (T^.tpTC = 3) THEN
- BEGIN
- i := T^.RecdDict;
- IF i <> x THEN
- WHILE i <> 0 DO BEGIN
- CoverWrapPost(x,i);
- D := AddrDict(UImg,i);
- S := AddrStub(D);
- IF DF = 'R' THEN i := RP^.ROB ELSE
- IF DF = 'S' THEN i := S^.sSHT
- ELSE i := 0;
- END {While I}
- END
- END {IF T <> Nil}
- END; {CoverWrapType}
-
- VAR i : Integer; {.CP08}
- BEGIN {CoverWrapUp}
- If CvrQuePtr <> Nil Then
- For i := 1 TO CvrQueTail DO
- WITH CvrQuePtr^[i] DO
- IF LocTyp = cvName THEN
- IF Public(AddrDict(UImg,LocLL)^.DForm) = 'Q'
- THEN CoverWrapType(LocLL)
- END; {CoverWrapUp}
-
- PROCEDURE CoverType(Arg : CvrRec); {.CP51}
- VAR T, TT : TypePtr; H:HashPtr; TTL : LL; I : Integer; L : Word;
- BEGIN {CoverType}
- T := TypePtr(PtrAdjust(UImg,Arg.LocLL));
- TTL := Arg.LocLL;
- IF T <> Nil THEN
- WITH T^ DO
- CASE tpTC OF
- $01: BEGIN
- IF AddrType(UImg,BaseType) <> Nil
- THEN Push(BaseType.UntLL,0,cvType,L);
- IF AddrType(UImg,BounDesc) <> Nil
- THEN Push(BounDesc.UntLL,0,cvType,L);
- END; {CASE $01}
- $02: IF RecdHash <> 0
- THEN Push(RecdHash,Arg.LocOwn,cvHash,L+1);
- $03: IF ObjtHash <> 0
- THEN Push(ObjtHash,ObjtName,cvHash,L+1);
- $04,
- $05: IF AddrType(UImg,FileType) <> Nil
- THEN Push(FileType.UntLL,0,cvType,L);
- $06: BEGIN
- IF AddrType(UImg,T^.PFRes) <> Nil
- THEN Push(T^.PFRes.UntLL,Arg.LocOwn,cvType,L);
- { Handle Parameter List Entries Here }
- FOR I := 1 TO T^.PNPrm DO WITH T^.PFPar[I] DO
- IF AddrType(UImg,fPTD) <> Nil
- THEN Push(fPTD.UntLL,Arg.LocOwn,cvType,L);
- END; {CASE $06}
- $07: IF AddrType(UImg,SetBase) <> Nil
- THEN Push(SetBase.UntLL,0,cvType,L);
- $08: IF AddrType(UImg,PtrBase) <> Nil
- THEN Push(PtrBase.UntLL,0,cvType,L);
- $09: BEGIN
- IF AddrType(UImg,StrBase) <> Nil
- THEN Push(StrBase.UntLL,0,cvType,L);
- IF AddrType(UImg,StrBound) <> Nil
- THEN Push(StrBound.UntLL,0,cvType,L);
- END; {CASE $09}
- $0C, $0D,
- $0E: IF AddrType(UImg,Cmpat) <> Nil
- THEN Push(Cmpat.UntLL,0,cvType,L);
- $0F: BEGIN
- IF AddrType(UImg,Cmpat) <> Nil
- THEN Push(Cmpat.UntLL,0,cvType,L);
- { now stack the SET descriptor that follows }
- TT := TypePtr(PtrAdjust(@Cmpat,SizeOf(T^.Cmpat)));
- Push(FormLL(UImg,TT),0,cvType,L);
- END; {CASE $0F}
- END; {CASE tpTC}
- END; {CoverType}
-
- PROCEDURE CoverDictStub(D : DNamePtr; {.CP38}
- S : DStubPtr; Owner : LL; L : Word);
-
- VAR T : TypePtr; H : HashPtr; I : Integer; LLDE : LL; C : Char;
- BEGIN {CoverDictStub}
- C := Public(D^.DForm);
- LLDE := FormLL(UImg,D);
- WITH S^ DO
- CASE C OF
- 'P': IF AddrType(UImg,sPTD) <> Nil
- THEN Push(sPTD.UntLL,0,cvType,L);
- 'Q': IF AddrType(UImg,sQTD) <> Nil
- THEN Push(sQTD.UntLL,LLDE,cvType,L);
- 'X': IF AddrType(UImg,sQTD) <> Nil
- THEN Push(sQTD.UntLL,0,cvType,L);
- 'R': IF AddrType(UImg,sRTD) <> Nil
- THEN Push(sRTD.UntLL,0,cvType,L);
- 'S': BEGIN
- IF sSHT <> 0 THEN Push(sSHT,LLDE,cvHash,L+1);
- T := AddrProcType(S);
- Push(FormLL(T,UImg),LLDE,cvType,L);
- IF AddrType(UImg,T^.PFRes) <> Nil
- THEN Push(T^.PFRes.UntLL,0,cvType,L);
- { Handle Parameter List Entries Here }
- FOR I := 1 TO T^.PNPrm DO WITH T^.PFPar[I] DO
- IF AddrType(UImg,fPTD) <> Nil
- THEN Push(fPTD.UntLL,0,cvType,L);
- IF (sSTp AND $02) <> 0 THEN
- Push(FormLL(UImg,@T^.PFPar[T^.PNPrm+1]),LLDE,cvINLN,L);
- END; {CASE 'S'}
-
- 'Y': BEGIN
- IF sYNU <> 0 THEN Push(sYNU,0,cvName,L);
- IF sYPU <> 0 THEN Push(sYPU,0,cvName,L);
- END; {CASE 'Y'}
-
- END; {CASE D^.DForm}
- END; {CoverDictStub}
-
- PROCEDURE CoverDictHdr(Arg : CvrRec); {.CP08}
- VAR D : DNamePtr; S : DStubPtr;
- BEGIN {CoverDictHdr}
- D := AddrDict(UImg,Arg.LocLL);
- S := AddrStub(D);
- CoverDictStub(D,S,Arg.LocLL,Arg.LocLvl);
- IF D^.HLink <> 0 Then Push(D^.HLink,Arg.LocOwn,cvName,Arg.LocLvl);
- END; {CoverDictHdr}
-
- PROCEDURE CoverHashTab(Arg : CvrRec); {.CP09}
- VAR HLim, I : LL; H : HashPtr; L : Word;
- BEGIN {CoverHashTab}
- L := Arg.LocLvl + 1;
- H := AddrHash(UImg,Arg.LocLL);
- HLim := (H^.Bas DIV SizeOf(LL));
- WITH H^ DO FOR I := 0 TO HLim DO
- IF Slt[I] <> 0 THEN Push(Slt[I],Arg.LocOwn,cvName,L);
- END; {CoverHashTab}
-
- Begin {CalcCovers} {.CP25}
-
- If UImg <> Nil Then
- With UImg^ Do Begin
- Push(UHIHT,UHUDH,cvHash,0); { INTERFACE Hash Table }
- Push(UHUDH,0,cvName,1); { Unit Dictionary Entry }
- IF UHIHT <> UHDHT
- THEN Push(UHDHT,UHDHT,cvHash,0); { Debug Rtn Hash Table }
- End;
-
- If (CvrQuePtr <> Nil) AND (CvrStkPtr <> Nil) Then
- WITH CvrWork DO
- WHILE CvrStkTop > 0 DO BEGIN
- Pop(CvrWork);
- IF NOT Queued(LocLL) THEN
- BEGIN
- EnQueue(CvrWork);
- CASE LocTyp OF
- cvName: CoverDictHdr(CvrWork); {DictHdr}
- cvHash: CoverHashTab(CvrWork); {HashTab}
- cvType: CoverType(CvrWork); {TypDesc}
- END; {CASE}
- END; {IF}
- END; {WHILE}
- CoverWrapUp;
-
- End; {CalcCovers}
-
- {.PA} {
- The following method uses the output of method "CalcCovers" to browse the
- symbol dictionary and discover relations involving the CSeg Map, the PROC
- Map, the Global VAR DSeg Map and the Typed CONST DSeg Map. The relations
- can involve Fix-Up data, the Trace Table, the Source File List, and the
- various code and data segments contained in the latter part of the unit
- file. These relations are saved in the heap for later retrieval by the
- print routines.
- }
-
- Procedure TUnit.IndexMaps; {.CP03}
-
- Var CodeBase, DataBase, FixCBase, FixDBase, NObj : Word;
-
- { This Procedure computes the size of each } {.CP27}
- { PROC and adds the result to the Xref map }
-
- Procedure SizeProcs;
- Var CodeLimit, I, J, K : Word; Pc, Pp : MapTabPtr; Rp, Rc : RMapPtr;
- Begin
- I := 0;
- CodeLimit := (UImg^.UHENC+$F) AND $FFF0 + UImg^.UHZCS;
- Rp := CvrRMaps[rPROC]; { Get RMap Pro Pointer }
- If Rp <> Nil Then
- Begin
- Pp := Rp^.RMapTabPtr; { Get Proc Ref Pointer }
- J := Rp^.RMapTabSiz; { Get Slot Count }
- End Else
- Begin Pp := Nil; J := 0 End;
- Rc := CvrRMaps[rCSEG]; { Get RMap Cod Pointer }
- If Rc <> Nil Then Pc := Rc^.RMapTabPtr; { Get CSeg Ref Pointer }
- If (J>0) AND (Rc <> Nil) Then
- While I < J-1 Do With Pp^[I] Do Begin
- If Pp^[I].MapCSM <> $FFFF Then
- If Pp^[I].MapCSM = Pp^[I+1].MapCSM
- Then Pp^[I].MapSiz := Pp^[I+1].MapEPT - Pp^[I].MapEPT
- Else Begin
- K := Pp^[I].MapCSM DIV SizeOf(CMapRec);
- Pp^[I].MapSiz := Pc^[K].MapLod + Pc^[K].MapSiz - Pp^[I].MapEPT;
- End;
- Inc(I);
- End;
- If (Pp <> Nil) AND (J>0) Then
- With Pp^[J-1] Do
- If MapCSM <> $FFFF
- Then MapSiz := Codelimit - MapEPT;
- End; {SizeProcs}
-
- { This Procedure Initializes the CSeg Xref Map } {.CP28}
- { and sets CSeg Load Points and Fix-Up Offsets }
-
- Procedure PrimeCSegs;
- Var Cx, Cn, I, N : Word; D : DMapTabPtr;
- C : CMapTabPtr; P : PMapPtr; Rmt, Rmv : MapTabPtr;
- Begin
- Rmt := CvrRMaps[rCSEG]^.RMapTabPtr;
- N := CvrRMaps[rCSEG]^.RMapTabSiz;
- Cn := CountCMapSlots(UImg);
- C := AddrCMapTab(UImg);
-
- If C <> Nil Then
- For Cx := 0 To Cn-1 Do { First, we add Info from CSeg }
- With C^[Cx], Rmt^[Cx] Do { Map to our CSeg MapRefTab and }
- Begin { Calc Fix-Up Offsets }
- MapTyp := mfCSEG;
- MapSrc := 0;
- MapLod := CodeBase;
- MapSiz := CSegCnt;
- Inc(CodeBase,CSegCnt);
- If CSegRel > 0 Then { We Have Fix-Ups for this CSeg }
- Begin
- MapFxI := FixCBase;
- FixCBase := FixCBase + CSegRel;
- MapFxJ := FixCBase - SizeOf(FixUpRec);
- End;
- End;
-
- { Similarly for Typed Constant Data Segments } {.CP40}
-
- Rmv := CvrRMaps[rCONS]^.RMapTabPtr;
- N := CvrRMaps[rCONS]^.RMapTabSiz;
- D := AddrDMapTab(UImg);
-
- If D <> Nil Then
- For Cx := 0 To N-1 Do { First, we add Info from DSeg }
- With D^[Cx], Rmv^[Cx] Do { Map to our DSeg MapRefTab and }
- Begin { Calc Fix-Up Offsets }
- If Cx = 0 Then MapTyp := mfPRUI; { flag unit init code }
- MapSrc := 0;
- MapSiz := DSegCnt;
- MapFxJ := DSegRel;
- If DSegOwn <> 0 Then
- Begin MapOwn := DSegOwn; MapTyp := mfTVMT End;
- End;
-
- { Now, we do a similar job for the PROC Map }
-
- Rmv := CvrRMaps[rPROC]^.RMapTabPtr;
- N := CvrRMaps[rPROC]^.RMapTabSiz;
- P := AddrPMapTab(UImg);
-
- If P <> Nil Then
- For Cx := 0 To N-1 Do
- With P^[Cx], Rmv^[Cx] Do
- Begin
- MapCSM := CSegOfs;
- MapEPT := CSegJmp;
- If MapCSM <> $FFFF Then
- Begin
- MapTyp := mfPROC;
- I := MapCSM DIV SizeOf(CMapRec);
- MapEPT := MapEPT + Rmt^[I].MapLod; { Relocate Entry Point }
- End;
- MapSrc := 0;
- End;
-
- End; { PrimeCSegs }
-
- { This Proc updates the CSeg Xref Table with data from the } {.CP57}
- { Trace and PROC Tables that allow us to determine which }
- { source file furnished the CSeg for the map entry. }
-
- Procedure FinalCSegs;
- Var Nc, I, Np, Sf, Sn: Word;
- Ps, Ph: SrcFilePtr; Pt: TraceRecPtr; PRc, PRp: MapTabPtr;
- Begin
- Ps := AddrSrcTabOff(UImg,0); Ph := Ps; { Source File List }
- Sf := 0; Sn := 0; { Total Src, non-Obj Files }
- While Ps <> Nil Do Begin
- Inc(Sf); { Inc Total Source Files }
- If Ps^.SrcFlag <> $05 Then Inc(Sn); { Inc Non-Obj File Count }
- Ps := AddrNxtSrc(UImg,Ps); { point to next src ntry }
- End;
- NObj := Sf - Sn; { Total *.OBJ Files } Ps := Ph; { Restore Ps }
-
- If (NObj > 0) AND (CvrRMaps[rCSEG] <> Nil) Then { have *.OBJ's in lst }
- Begin
- PRc:= CvrRMaps[rCSEG]^.RMapTabPtr;
- Nc := CvrRMaps[rCSEG]^.RMapTabSiz;
- For I := 1 to Sn Do Ps := AddrNxtSrc(UImg,Ps);
- For I := (Nc-NObj) To Nc-1 Do
- With PRc^[I] Do Begin
- MapSrc := FormLL(Ph,Ps);
- Ps := AddrNxtSrc(UImg,Ps);
- End; { *.OBJ Handler }
-
- { If Pascal Include Files are present, Only the Trace Table Knows }
- { and this is noted only if these files contain PROCs. This can }
- { be used to get the source file (actual) in these cases. Scan }
- { the trace table and compare its PROC pointer with PROC Name LL }
- { in our PROC Ref table. If match, then trace entry has source }
- { info that applies to this proc (which is part of some CSeg) and }
- { the PROC Ref entry has the CSeg Map Offset which we use to make }
- { the linkage to our CSeg Ref table to save source file offset. }
-
- Pt := AddrTraceTab(UImg);
- If CvrRMaps[rPROC] <> Nil Then
- Begin
- PRp := CvrRMaps[rPROC]^.RMapTabPtr;
- Np := CvrRMaps[rPROC]^.RMapTabSiz;
- While Pt <> Nil Do With Pt^ Do Begin {For ALL Trace Entries}
- I := 0;
- While I < Np Do With PRp^[I] Do Begin {For ALL PROC Entries }
- If MapOwn = Trname Then {Proc has Trace Entry }
- Begin
- PRc^[MapCSM DIV SizeOf(CMapRec)].MapSrc := Trfill;
- I := Np; {quit loop and try next trace entry}
- End;
- Inc(I);
- End;
- Pt := AddrNxtTrace(UImg,Pt);
- End;
- End;
- End;
- End; {FinalCSegs}
-
- { This Procedure updates the CONST Xref Table with data from }{.CP49}
- { various sources to get offsets to Fix-Up data and to try to }
- { locate the file in the Source File List that contributed }
- { this entry. Any entry NOT defined in the Pascal Source will }
- { have mfNULL as its MapTyp. We will change such entries to }
- { mfXTRN and try to decide who spawned them. This problem is }
- { strictly undecidable. We can guess that a Fix-Up in some }
- { CSeg that references our entry is from the *.OBJ spawned the }
- { block, but that is the closest we can get to the truth. }
-
- Procedure FinalCONST;
- Var I, N : Word; HaveXtrn : Boolean; Rmt : MapTabPtr;
- Begin
- If CvrRMaps[rCONS] <> Nil Then
- Begin
- Rmt := CvrRMaps[rCONS]^.RMapTabPtr;
- N := CvrRMaps[rCONS]^.RMapTabSiz;
- HaveXtrn := False;
-
- If (N > 0) AND (Rmt <> Nil) Then
- Begin
- For I := 0 To N-1 Do With Rmt^[I] Do Begin
- MapLod := DataBase;
- DataBase := DataBase + MapSiz;
- If MapFxJ > 0 Then
- Begin
- MapFxI := FixDBase;
- Inc(FixDBase,MapFxJ);
- MapFxJ := FixDBase - SizeOf(FixUpRec);
- End;
- If NObj > 0 Then If MapTyp = mfNULL Then
- Begin
- MapTyp := mfXTRN;
- HaveXtrn := True;
- End;
- End; {For} { Fix-Up Offsets are now set }
- { Source File problem deferred until later }
- End;
- End;
-
- If CvrRMaps[rVARS] <> Nil Then
- Begin
- Rmt := CvrRMaps[rVARS]^.RMapTabPtr; { Classify VARS Too }
- N := CvrRMaps[rVARS]^.RMapTabSiz;
- If (N > 0) AND (Rmt <> Nil) AND (NObj > 0)
- Then For I := 0 To N-1 Do With Rmt^[I] Do
- If MapTyp = mfNULL Then MapTyp := mfXTRN
- End;
- End; {FinalCONST}
-
- Var I, J, DHT, IHT : Word; C : Char; {.CP33}
- Pn : DNamePtr; Ps : DStubPtr; Pv : VarStubPtr; Pm, Pc : RMapPtr;
- Pp : PMapRecPtr; Tc, Tv, Td : DMapRecPtr; V : CvrRec; Q, Qc : MapRefRec;
- Ndx : MapClass; SystemUnit, InINTF : Boolean;
- Begin {IndexMaps}
-
- For Ndx := rPROC To rCONS Do
- If CvrRMaps[Ndx] <> Nil Then CvrRMaps[Ndx]^.Done;
-
- CvrRMaps[rCONS] := New(RMapPtr,Init(UImg^.UHDMT-UImg^.UHTMT));
- CvrRMaps[rVARS] := New(RMapPtr,Init(UImg^.UHxxy-UImg^.UHDMT));
- CvrRMaps[rPROC] := New(RMapPtr,Init(UImg^.UHCMT-UImg^.UHPMT));
- CvrRMaps[rCSEG] := New(RMapPtr,Init(UImg^.UHTMT-UImg^.UHCMT));
-
- CodeBase := (UImg^.UHENC + $F) AND $FFF0;
- DataBase := (UImg^.UHZCS + CodeBase +$F) AND $FFF0;
- FixCBase := (UImg^.UHZDT + DataBase +$F) AND $FFF0;
- DHT := UImg^.UHDHT; IHT := UImg^.UHIHT;
- SystemUnit := IsSystemUnit(UImg);
-
- If CvrRMaps[rCSEG]^.RMapTabSiz > 0 { Initialize CSeg Map Refs }
- Then PrimeCSegs;
-
- FixDBase := (FixCBase +$F) AND $FFF0; { VMT Fix-Ups Start Here }
- Pc := CvrRMaps[rCSEG]; { Get Method Pointer }
-
- For I := 1 To CvrQueTail Do Begin { Get CONST/VAR Mapping }
- V := CvrQuePtr^[I];
- If V.LocTyp = cvName Then
- Begin
- Tc := Ptr(Seg(UImg^),Ofs(UImg^)+UImg^.UHTMT); { CONS Map }
- Tv := Ptr(Seg(UImg^),Ofs(UImg^)+UImg^.UHDMT); { DSeg Map }
- Pn := Ptr(Seg(UImg^),Ofs(UImg^)+V.LocLL);
- Ps := AddrStub(Pn); C := Public(Pn^.DForm);
-
- If C = 'R' Then { a data instance of some kind } {.CP37}
- Begin
- If Ps^.sRAM < $02 Then { a global variable or typed const }
- Begin
- Pv := @Ps^.sRVF;
- J := Pv^.TOB;
- InINTF := (IHT = DHT) OR SystemUnit OR (DHT > V.LocLL);
-
- If Ps^.sRAM = $00 Then
- Begin { it's a Global Variable }
- Pm := CvrRMaps[rVARS];
- Pm^.FetchRef(Q,Pv^.TOB);
- Td := Ptr(Seg(Tv^),Ofs(Tv^)+J);
- Q.MapSiz := Td^.DSegCnt;
- If InINTF Then Q.MapTyp := mfINTF
- Else Q.MapTyp := mfIMPL;
- Pm^.StoreRef(Q,Pv^.TOB);
- End Else
- Begin { it's a Typed Constant }
- Pm := CvrRMaps[rCONS];
- Pm^.FetchRef(Q,Pv^.TOB);
- Td := Ptr(Seg(Tc^),Ofs(Tc^)+J);
- If Td^.DSegOwn <> 0 Then Begin
- Q.MapTyp := mfTVMT;
- Q.MapOwn := Td^.DSegOwn; { Owner is OBJECT Name }
- End Else
- If V.LocLvl = 1
- Then If InINTF Then Q.MapTyp := mfINTF
- Else Q.MapTyp := mfIMPL
- Else Begin
- Q.MapTyp := mfNEST;
- Q.MapOwn := V.LocOwn; { Owner is PROC scope }
- End;
- Pm^.StoreRef(Q,Pv^.TOB);
- End; { Typed Constant }
- End; { Variable/Constant }
- End { Type 'R' Stub }
-
- Else { Check for PROC Map } {.CP20}
- If C = 'S' Then { It's a PROC ...... }
- If (Ps^.sSTP AND $02) = 0 Then { ... AND NOT INLINE }
- Begin
- Pm := CvrRMaps[rPROC]; { Get Method Pointer }
- Pm^.FetchRef(Q,Ps^.sSPM);
- Q.MapOwn := V.LocLL; { Get PROC Name Offset }
- Pm^.StoreRef(Q,Ps^.sSPM);
- End; { Type 'S' Stub }
- End; { DName Entry }
- End; { FOR }
-
- If CvrRMaps[rCSEG]^.RMapTabSiz > 0 Then FinalCSegs; { Finish CSeg Refs }
-
- CvrRMaps[rPROC]^.SortPMap(CSegOrder); { Sort PROCS in Load Order }
- SizeProcs; { Get Proc Size(Bytes) }
- CvrRMaps[rPROC]^.SortPMap(PMapOrder); { Sort PROCS in PMap Order }
- If CvrRMaps[rCONS] <> Nil Then FinalCONST; { Finish CONST Refs }
-
- End; {IndexMaps}
-
- (* E N D M E T H O D S *)
-
- Function FindCover(U : UnitPtr) : TUnitPtr; {.CP11}
- Var S : TUnitPtr;
- Begin
- FindCover := Nil; S := LstRoot;
- While S <> Nil Do
- If S^.UImg <> U Then S := S^.Link Else
- Begin
- FindCover := S;
- S := Nil
- End;
- End; {FindCover}
-
- PROCEDURE SortProcRefs (Mode : SortMode); {.CP06}
- Begin
- If LstRoot <> Nil Then
- If LstRoot^.CvrRMaps[rPROC] <> Nil
- Then LstRoot^.CvrRMaps[rPROC]^.SortPmap(Mode);
- End;
-
- PROCEDURE FetchMapRef (VAR S : MapRefRec; {.CP10}
- C : MapClass;
- Offset: Word);
- Var Q : TUnitPtr;
- Begin
- Q := LstRoot; S := NullMap;
- If Q <> Nil Then
- If Q^.CvrRMaps[C] <> Nil
- Then Q^.CvrRMaps[C]^.FetchRef(S,Offset);
- End;
-
- PROCEDURE FetchSurveyRec (VAR S : SurveyRec); {.CP18}
- Var Q : CvrRec;
- Begin
- S.LocTyp := cvNULL; S.LocLL := 0; S.LocOwn := 0; S.LocNxt := 0;
- If LstRoot <> Nil Then With LstRoot^ Do
- If UImg <> Nil Then If CvrQuePtr <> Nil Then
- Begin
- If CvrQueHead < CvrQueTail Then
- Begin
- Inc(CvrQueHead);
- Q := CvrQuePtr^[CvrQueHead];
- S.LocTyp := Q.LocTyp; S.LocLL := Q.LocLL;
- S.LocOwn := Q.LocOwn; S.LocNxt := UImg^.UHPMT
- End;
- If CvrQueHead < CvrQueTail
- Then S.LocNxt := CvrQuePtr^[CvrQueHead+1].LocLL;
- End;
- End; {FetchSurveyRec}
-
- Procedure PurgeAllUnits; {.CP12}
- Var P, Q: TUnitPtr;
- Begin
- P := Nil; Q := LstRoot;
- While Q <> Nil Do
- Begin
- P := Q^.Link;
- Q^.Done;
- Q := P;
- End;
- LstRoot := Nil;
- End; {PurgeAllUnits}
-
- Function FindUnit(N: _UnitName) : UnitPtr; {.CP12}
- Var P : TUnitPtr; U : UnitPtr;
- Begin
- U := Nil; P := LstRoot;
- While P <> Nil Do
- If P^.Name <> N Then P := P^.Link Else
- Begin
- U := P^.UImg;
- P := Nil
- End;
- FindUnit := U;
- End;
-
- PROCEDURE SurveyUnit(U : UnitPtr); {.CP15}
- Var S : TUnitPtr;
- BEGIN {SurveyUnit}
- S := FindCover(U); { Locate Proper TUnit }
- If S <> Nil Then
- Begin
- S^.CalcCovers; { Analyze Dictionary }
- S^.DisposeStack; { Release Cover Stack }
- S^.PackQueue; { Trim Cover Queue }
- If S = LstRoot Then { If Initial Unit Then }
- S^.IndexMaps; { Cross-Index All Maps }
- End;
- END; {SurveyUnit}
-
- PROCEDURE ResolveLG(N: _UnitName; L : LG; VAR R: RespLG); {.CP20}
- Var S : RespLG; U : UnitPtr; T : TUnitPtr; Q: CvrTabPtr;
- W : Word;
- Begin
- S.Uptr := Nil; S.Ownr := $FFFF; U := FindUnit(N);
- If U <> Nil Then
- Begin
- T := FindCover(U);
- W := T^.QueuePos(L.UntLL);
- Q := T^.CvrQuePtr;
- If NOT (W > T^.CvrQueTail) Then
- If L.UntLL = Q^[W].LocLL Then
- Begin
- S.Uptr := U;
- S.Ownr := Q^[W].LocOwn;
- End;
- End;
- R := S;
- End; { ResolveLG }
-
- Var LoaderPath: _FileXpnd;
-
- Procedure UnitLoader( Path : Dos.PathStr; {.CP12}
- Name : _UnitName;
- Optn : UnitMode;
- VAR Core : Word;
- VAR Locn : UnitPtr);
-
- VAR SaveMode,UnitVersion : Word; U : UnitPtr;
- FileId : _FileSpec;
- FileDir : Dos.DirStr; FileName : Dos.NameStr;
- FileExtn : Dos.ExtStr; FilePath : Dos.PathStr;
- WorkArea : Array[0..3] Of _Paragraph;
- UnitFile : File; EnvirPth : String;
-
- Function UnitSize( U : UnitPtr) : Word; {.CP13}
- VAR EyeBall : String[4];
- Begin
- EyeBall[0] := Chr(SizeOf(EyeBall)-1);
- Move(U^,EyeBall[1],SizeOf(EyeBall)-1);
- If EyeBall <> _UnitEye
- Then UnitSize := 0
- Else
- UnitSize := ((U^.UHENC + $F) AND $FFF0) +
- ((U^.UHZCS + $F) AND $FFF0) +
- ((U^.UHZDT + $F) AND $FFF0) +
- ((U^.UHZFA + $F) AND $FFF0) +
- ((U^.UHZFT + $F) AND $FFF0);
- End; {UnitSize}
-
- Function FileExists( N : _FileSpec {.CP13}
- {X : Dos.ExtStr}) : Boolean;
- Begin
- FilePath := FSearch(N,EnvirPth);
- If FilePath <> '' Then
- Begin
- FilePath := FExpand(FilePath);
- FSplit(FilePath,FileDir,FileName,FileExtn);
- FileId := N;
- FileExists := True
- End
- Else FileExists := False;
- End; {FileExists}
-
- Procedure OpenUnitFile(P : Dos.PathStr; N : _FileSpec); {.CP08}
- Begin
- Assign(UnitFile,P+N);
- SaveMode := FileMode;
- FileMode := 0;
- Reset(UnitFile,SizeOf(_Paragraph));
- FileMode := SaveMode;
- End;
-
- Procedure InstallUnit(U : UnitPtr; N : _UnitName; Su : Word);{.CP24}
- Var Sk, Sr : Word; T, V : TUnitPtr;
- Begin
- Sk := Su; (*
- If Optn = Partial Then With U^ Do { Keep Only Dictionaries }
- Begin
- Sk := UHPMT;
- T := PtrNormal(Ptr(Seg(U^),Ofs(U^)+Sk));
- Sr := (Su - Sk) AND $FFF0;
- FreeMem(T,Sr); { Release non-dictionary part of unit }
- End; *)
- T := New(TUnitPtr,Init(N,U,Sk)); { build placeholder }
- If T <> Nil Then
- Begin
- If LstRoot = Nil
- Then LstRoot := T Else { add to chain }
- Begin
- V := LstRoot;
- While V^.Link <> Nil Do V := V^.Link;
- V^.Link := T;
- End;
- LoaderPath := FileDir+FileId;
- Core := Sk; { Say How Much of Unit Loaded }
- Locn := T^.UImg; { Point to Unit Load Address }
- End;
- End; {InstallUnit}
-
- Procedure CheckLibrary(N : _UnitName); {.CP26}
- Var U : UnitPtr; Su, Sf, Sk, Fp : Word; Ps : DStubPtr; Pn : DNamePtr;
- Begin
- OpenUnitFile(FileDir,FileId);
- Sf := FileSize(UnitFile);
- Fp := 0;
- While Fp < Sf Do Begin
- Seek(UnitFile,Fp);
- BlockRead(UnitFile,WorkArea,4);
- U := @WorkArea;
- Su := UnitSize(U);
- Sk := Su;
- If Optn = Partial Then Sk := (U^.UHPMT + $F) AND $FFF0;
- GetMem(U,Sk);
- If U <> Nil Then
- Begin
- Seek(UnitFile,Fp);
- BlockRead(UnitFile,U^,Sk SHR 4);
- Pn := DNamePtr(Ptr(Seg(U^),Ofs(U^)+U^.UHUDH));
- Ps := AddrStub(Pn);
- If (N <> Pn^.DSymb) OR
- ((Optn = Partial) AND (Ps^.sYCS <> UnitVersion)) Then
- Begin
- FreeMem(U,Sk);
- Inc(Fp,Su SHR 4);
- End Else
- Begin
- InstallUnit(U,N,Sk);
- Fp := Sf
- End
- End Else Fp := Sf;
- End;
- Close(UnitFile);
- End; {CheckLibrary}
-
- Procedure FetchUnit(N : _UnitName); {.CP17}
- Var U : UnitPtr; Su, Sf, Sk : Word; Ps : DStubPtr; Pn : DNamePtr;
- Begin
- OpenUnitFile(FileDir,FileId);
- Sf := FileSize(UnitFile) SHL 4;
- Seek(UnitFile,0);
- BlockRead(UnitFile,WorkArea,4);
- Seek(UnitFile,0);
- U := @WorkArea;
- Su := UnitSize(U);
- Sk := Su;
- If Optn = Partial Then Sk := (U^.UHPMT + $F) AND $FFF0;
- GetMem(U,Sk);
- If U <> Nil Then
- Begin
- BlockRead(UnitFile,U^,Sk SHR 4);
- Pn := DNamePtr(Ptr(Seg(U^),Ofs(U^)+U^.UHUDH));
- Ps := AddrStub(Pn);
- If (N <> Pn^.DSymb) OR
- ((Optn = Partial) AND (Ps^.sYCS <> UnitVersion))
- Then FreeMem(U,Sk)
- Else InstallUnit(U,N,Sk);
- End;
- Close(UnitFile);
- End; {FetchUnit}
-
- VAR I : Word; {.CP10}
- Begin {UnitLoader}
- UnitVersion := Core;
- Core := 0;
- Locn := Nil;
- LoaderPath := '';
- If Path = ''
- Then EnvirPth := GetEnv('PATH')
- Else EnvirPth := Path;
- If FileExists(Name+'.TPU') Then FetchUnit(Name) Else
- If FileExists(_Library) Then CheckLibrary(Name);
- End; {UnitLoader}
-
- Function AnalyzeUnit(Name: _UnitName; {.CP32}
- Path: String): UnitPtr;
- Var U, Z: UnitPtr; N: DNamePtr; S: DStubPtr; USize: Word;
- Begin
- UnitLoader(Path,Name,Entire,USize,U); { Load Entire Unit }
- AnalyzeUnit := U; { Save Unit Pointer }
- If U <> Nil Then
- Begin
- PutTxt('Unit ('+Name+')');
- SetCol(17);
- PutTxt(' loaded from '+LoaderPath);
- SetCol(1);
- SurveyUnit(U); { Analyze Unit }
- N := DNamePtr(PtrAdjust(U,U^.UHUDH)); { Point to its name }
- S := AddrStub(N); { Point to its stub }
- While S^.sYNU <> 0 Do { if successor unit }
- Begin
- N := DNamePtr(PtrAdjust(U,S^.sYNU)); { Point to Name }
- S := AddrStub(N); { Point to Stub }
- USize := S^.sYCS; { Load Version }
- UnitLoader(Path,N^.DSymb,Partial,USize,Z); { Load Partial }
- If Z <> Nil Then
- Begin
- PutTxt('Unit ('+N^.DSymb+')');
- SetCol(17);
- PutTxt(' loaded from '+LoaderPath);
- SetCol(1);
- SurveyUnit(Z); { Get its Cover }
- End;
- End; { Until all Units Handled }
- End;
- End; {AnalyzeUnit}
-
- End.