home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turbo Toolbox
/
Turbo_Toolbox.iso
/
1991
/
06
/
tricks
/
realloc2.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1991-03-06
|
10KB
|
225 lines
(* ------------------------------------------------------ *)
(* REALLOC2.PAS *)
(* Angepaßte Version für Turbo-Pascal 6.0 *)
(* (c) 1991 Gerd Cebulla & TOOLBOX *)
(* ------------------------------------------------------ *)
{$X+}
UNIT ReAlloc2;
INTERFACE
FUNCTION ChangeMem(P : Pointer;
OldSize, NewSize : WORD) : Pointer;
IMPLEMENTATION
FUNCTION AbsAddr (P : Pointer) : LONGINT;
{ Wandelt einen Zeiger im Format Segment:Offset in eine }
{ absolute Adresse im Bereich 0..$FFFFF um. }
BEGIN
AbsAddr := LONGINT(Seg(P^)) SHL 4 + Ofs(P^);
END;
FUNCTION NormPtr(Addr : LONGINT) : Pointer;
{ Konvertiert eine absolute Adresse in einen }
{ "normalisierten" Zeiger, d.h., der Offsetanteil des }
{ Funktionsergebnisses liegt immer zwischen 0 und 15. }
BEGIN
NormPtr := Ptr(Addr DIV 16, Addr MOD 16);
END;
FUNCTION ChangeMem(P : Pointer;
OldSize, NewSize : WORD) : Pointer;
{ Verändert die Größe des für die dynamische Variable P^ }
{ reservierten Speicherbereichs. Bei erfolgreicher }
{ Ausführung zeigt das Funktionsergebnis auf die neue }
{ Adresse der dynamischen Variable, ansonsten wird der }
{ Wert NIL zurückgeliefert. }
TYPE
FreePtr = ^FreeRec;
FreeRec = RECORD {Aufbau eines Fragmentlisteneintrags}
Next : FreePtr; {Zeiger auf nächsten Eintrag}
Size : Pointer; {Größe des freien Bereichs}
END;
HeapFunc = FUNCTION (Size : WORD) : INTEGER;
{wird als Typecast-Operator beim Aufruf}
{der HeapError-Funktion benutzt}
VAR
NewP, {neue Adresse der dyn. Var.}
OldPEnd, {alte Endadresse der dyn. Var.}
NewPEnd : Pointer; {neue Endadresse der dyn. Var.}
FPred, {Zeiger auf Fragmentlisteneintrag}
{für freien Speicherplatz unterhalb von P^}
FSucc : FreePtr; {dto. oberhalb von P^}
Frei : LONGINT; {verfügbarer Speicherplatz}
RetCode : INTEGER; {Rückgabewert der HeapError-Funktion}
Fehler : BOOLEAN; {True, wenn nicht genug freier Heap}
BEGIN
IF (OldSize = 0) AND (NewSize = 0) THEN
ChangeMem := NIL
ELSE IF OldSize = 0 THEN BEGIN
GetMem (P, NewSize); {dyn. Var. neu anlegen}
ChangeMem := P;
END {else if OldSize = 0}
ELSE IF NewSize = 0 THEN BEGIN
FreeMem (P, OldSize); {dyn. Var. löschen}
ChangeMem := NIL;
END {else if NewSize = 0}
ELSE BEGIN
{Speicher wird immer in Schritten von 8 Byte }
{zugeteilt, daher OldSize und NewSize aufrunden}
OldSize := (OldSize + 7) AND NOT 7;
NewSize := (NewSize + 7) AND NOT 7;
P := NormPtr (AbsAddr (P)); {P normalisieren}
OldPEnd := NormPtr (AbsAddr (P) + OldSize);
REPEAT {until not Fehler}
Fehler := FALSE;
IF (LONGINT (P) < LONGINT (HeapOrg)) OR
(LONGINT (OldPEnd) > LONGINT (HeapPtr)) THEN
{zeigt P auf eine Adresse außerhalb des Heap?}
RunError (204); {"invalid pointer operation"}
IF OldSize = NewSize THEN
{Größe von P^ bleibt gleich?}
ChangeMem := P {dann fertig}
ELSE BEGIN
FPred := @FreeList; {Zeiger auf Root-Record}
FSucc := FPred^.Next; {1. Fragmentlisteneintrag}
WHILE LONGINT (FSucc) < LONGINT (P) DO BEGIN
{Fragmentliste durchsuchen}
FPred := FSucc;
FSucc := FPred^.Next;
END; {while}
IF NewSize < OldSize THEN BEGIN
{den für P^ reservierten Speicher verkleinern}
NewPEnd := NormPtr (AbsAddr (P) + NewSize);
IF HeapPtr = OldPEnd THEN
HeapPtr := NewPEnd
ELSE IF FSucc = OldPEnd THEN BEGIN
FreePtr (NewPEnd)^.Next := FSucc^.Next;
FreePtr (NewPEnd)^.Size := NormPtr
(OldSize - NewSize + AbsAddr (FSucc^.Size));
END {else if FSucc = OldPEnd}
ELSE BEGIN
FreePtr (NewPEnd)^.Next := FSucc;
FreePtr (NewPEnd)^.Size := NormPtr
(OldSize - NewSize);
END; {else}
FPred^.Next := NewPEnd;
ChangeMem := P;
END {if NewSize < OldSize}
ELSE BEGIN
{freien Speicherplatz oberhalb von P^ berechnen}
IF HeapPtr = OldPEnd THEN
Frei := AbsAddr (HeapEnd) - AbsAddr (HeapPtr)
ELSE IF FSucc = OldPEnd THEN
Frei := AbsAddr (FSucc^.Size)
ELSE
Frei := 0;
Inc (Frei, OldSize);
{den von P^ belegten Speicherplatz addieren}
IF Frei >= NewSize THEN BEGIN
{genug Platz oberhalb von P^?}
{dann entsprechend Speicher reservieren}
NewPEnd := NormPtr (AbsAddr (P) + NewSize);
IF HeapPtr = OldPEnd THEN BEGIN
HeapPtr := NewPEnd;
FPred^.Next := HeapPtr;
IF HeapError <> NIL THEN
HeapFunc (HeapError) (0);
{neue Konvention bei Turbo-Pascal 6.0:}
{Erhöhungen der Heap-Spitze müssen der}
{HeapError-Funktion gemeldet werden}
END {if HeapPtr = OldPEnd}
ELSE IF Frei = NewSize THEN
FPred^.Next := FSucc^.Next
ELSE BEGIN
FPred^.Next := NewPEnd;
FreePtr (NewPEnd)^.Next := FSucc^.Next;
FreePtr (NewPEnd)^.Size :=
NormPtr (Frei - NewSize);
END; {else}
ChangeMem := P;
END {if Frei >= NewSize}
ELSE BEGIN
{freien Speicher unterhalb von P^ ermitteln}
IF NormPtr (AbsAddr (FPred) +
AbsAddr (FPred^.Size)) = P THEN
Inc (Frei, AbsAddr (FPred^.Size));
IF Frei >= NewSize THEN BEGIN
{genug Platz unterhalb von P^?}
{dann P^ nach unten verschieben}
{und Fragmentliste aktualisieren}
NewP := FPred;
NewPEnd := NormPtr (AbsAddr (NewP) +
NewSize);
Move (P^, NewP^, OldSize);
FPred := @FreeList;
WHILE FPred^.Next <> NewP DO
FPred := FPred^.Next;
IF HeapPtr = OldPEnd THEN BEGIN
HeapPtr := NewPEnd;
FPred^.Next := HeapPtr;
IF (LONGINT (NewPEnd) > LONGINT (OldPEnd))
AND (HeapError <> NIL) THEN
HeapFunc (HeapError) (0);
END {if HeapPtr = OldPEnd}
ELSE IF FSucc = OldPEnd THEN
IF Frei = NewSize THEN
FPred^.Next := FSucc^.Next
ELSE BEGIN
FreePtr (NewPEnd)^.Next := FSucc^.Next;
FreePtr (NewPEnd)^.Size :=
NormPtr (Frei - NewSize);
FPred^.Next := NewPEnd;
END {else}
ELSE IF NewPEnd = OldPEnd THEN
FPred^.Next := FSucc
ELSE BEGIN
FreePtr (NewPEnd)^.Next := FSucc;
FreePtr (NewPEnd)^.Size :=
NormPtr (Frei - NewSize);
FPred^.Next := NewPEnd;
END; {else}
ChangeMem := NewP;
END {if Frei >= NewSize}
ELSE BEGIN {weder ober- noch unterhalb}
{von P^ genug Platz?}
{dann anderswo Speicher reservieren,}
{P^ kopieren und ursprünglichen}
{Speicherbereich freigeben}
GetMem (NewP, NewSize);
IF NewP <> NIL THEN BEGIN
Move (P^, NewP^, OldSize);
FreeMem (P, OldSize);
ChangeMem := NewP;
END {if NewP <> nil}
ELSE
Fehler := TRUE; {nicht genug Heap frei}
END; {else}
END; {else}
END; {else}
END; {else}
IF Fehler THEN BEGIN
IF HeapError = NIL THEN
{keine Heapfehlerbehandlung installiert?}
RunError (203) {"heap overflow error"}
ELSE BEGIN {sonst benutzerdefinierte}
{Heapfehlerroutine aufrufen}
RetCode := HeapFunc (HeapError) (NewSize);
IF RetCode = 0 THEN
RunError (203) {"heap overflow error"}
ELSE IF RetCode = 1 THEN BEGIN
Fehler := FALSE;
ChangeMem := NIL;
END; {else if RetCode = 1}
END; {else}
END; {if Fehler}
UNTIL NOT Fehler;
END; {else}
END; {ChangeMem}
END.
(* ------------------------------------------------------ *)
(* REALLOC2.PAS *)