home *** CD-ROM | disk | FTP | other *** search
- (* ------------------------------------------------------ *)
- (* 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 *)
-