799 lines
22 KiB
C
Executable File
799 lines
22 KiB
C
Executable File
/*
|
|
Copyright (C) 1994-1995 Apogee Software, Ltd.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
// Z_zone.c
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef DOS
|
|
#include <dos.h>
|
|
#include <conio.h>
|
|
#endif
|
|
|
|
#include "rt_def.h"
|
|
#include "_z_zone.h"
|
|
#include "z_zone.h"
|
|
#include "rt_util.h"
|
|
#include "develop.h"
|
|
#include "rt_net.h"
|
|
|
|
#if (DEVELOPMENT == 1)
|
|
#include "rt_main.h"
|
|
#endif
|
|
//MED
|
|
#include "memcheck.h"
|
|
|
|
int lowmemory=0;
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
ZONE MEMORY ALLOCATION
|
|
|
|
There is never any space between memblocks, and there will never be two
|
|
contiguous free memblocks.
|
|
|
|
The rover can be left pointing at a non-empty block
|
|
|
|
It is of no value to free a cachable block, because it will get overwritten
|
|
automatically if needed
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
//Globals
|
|
|
|
int zonememorystarted=0;
|
|
|
|
// Statics
|
|
|
|
static memzone_t *mainzone;
|
|
static memzone_t *levelzone;
|
|
static int levelzonesize=LEVELZONESIZE;
|
|
static struct meminfo
|
|
{
|
|
unsigned LargestBlockAvail;
|
|
unsigned MaxUnlockedPage;
|
|
unsigned LargestLockablePage;
|
|
unsigned LinAddrSpace;
|
|
unsigned NumFreePagesAvail;
|
|
unsigned NumPhysicalPagesFree;
|
|
unsigned TotalPhysicalPages;
|
|
unsigned FreeLinAddrSpace;
|
|
unsigned SizeOfPageFile;
|
|
unsigned Reserved[3];
|
|
} MemInfo;
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_ClearZone
|
|
=
|
|
========================
|
|
*/
|
|
|
|
void Z_ClearZone (memzone_t *zone)
|
|
{
|
|
memblock_t *block;
|
|
|
|
// set the entire zone to one free block
|
|
|
|
zone->blocklist.next = zone->blocklist.prev = block =
|
|
(memblock_t *)( (byte *)zone + sizeof(memzone_t) );
|
|
zone->blocklist.user = (void *)zone;
|
|
zone->blocklist.tag = PU_STATIC;
|
|
zone->rover = block;
|
|
|
|
block->prev = block->next = &zone->blocklist;
|
|
block->user = NULL; // free block
|
|
block->size = zone->size - sizeof(memzone_t);
|
|
}
|
|
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_AllocateZone
|
|
=
|
|
========================
|
|
*/
|
|
|
|
memzone_t *Z_AllocateZone (int size)
|
|
{
|
|
memzone_t *header;
|
|
|
|
header = malloc (size+sizeof(memzone_t));
|
|
if (!header)
|
|
Error ("Z_AllocateZone: Couldn't malloc %zd bytes avail=%d\n",
|
|
size+sizeof(memzone_t), Z_AvailHeap());
|
|
header->size = size;
|
|
Z_ClearZone (header);
|
|
return header;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_Init
|
|
=
|
|
========================
|
|
*/
|
|
void Z_Init (int size, int min)
|
|
{
|
|
int maxsize;
|
|
int sz;
|
|
|
|
if (zonememorystarted==1)
|
|
return;
|
|
zonememorystarted=1;
|
|
|
|
sz = GamePacketSize();
|
|
|
|
sz*=MAXCMDS;
|
|
|
|
if (ConsoleIsServer() == true)
|
|
levelzonesize+=((numplayers*2)+1)*sz;
|
|
else
|
|
levelzonesize+=(numplayers+1)*sz;
|
|
|
|
maxsize=((int)(Z_AvailHeap())-size-levelzonesize);
|
|
if (maxsize<min)
|
|
{
|
|
UL_DisplayMemoryError (min-maxsize);
|
|
}
|
|
if (maxsize>MAXMEMORYSIZE)
|
|
maxsize=(MAXMEMORYSIZE-levelzonesize);
|
|
|
|
mainzone = Z_AllocateZone (maxsize);
|
|
levelzone = Z_AllocateZone (levelzonesize);
|
|
|
|
if (!quiet)
|
|
printf("Z_INIT: %ld bytes\n",(long int)(maxsize+levelzonesize));
|
|
|
|
if (maxsize<(min+(min>>1)))
|
|
{
|
|
lowmemory = 1;
|
|
|
|
printf("==============================================================================\n");
|
|
printf("WARNING: You are running ROTT with very little memory. ROTT runs best with\n");
|
|
printf("8 Megabytes of memory and no TSR's loaded in memory. If you can free up more\n");
|
|
printf("memory for ROTT then you should press CTRL-BREAK at this time. If you are\n");
|
|
printf("unable to do this you will experience momentary pauses in game-play whenever\n");
|
|
printf("you enter new areas of the game as well as an overall decreased performance.\n");
|
|
printf(" Press any key to continue\n");
|
|
printf("==============================================================================\n");
|
|
getch();
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_ShutDown
|
|
=
|
|
========================
|
|
*/
|
|
|
|
void Z_ShutDown( void )
|
|
{
|
|
if (zonememorystarted==0)
|
|
return;
|
|
zonememorystarted=0;
|
|
free(mainzone);
|
|
free(levelzone);
|
|
}
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_GetSize
|
|
=
|
|
========================
|
|
*/
|
|
|
|
int Z_GetSize (void *ptr)
|
|
{
|
|
memblock_t *block;
|
|
|
|
block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
|
|
return (block->size - sizeof(memblock_t));
|
|
}
|
|
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_Free
|
|
=
|
|
========================
|
|
*/
|
|
|
|
void Z_Free (void *ptr)
|
|
{
|
|
memblock_t *block, *other;
|
|
|
|
block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
|
|
if (!block->user)
|
|
Error ("Z_Free: freed a freed pointer");
|
|
|
|
if (block->user > (void **)0x100) // smaller values are not pointers
|
|
*block->user = 0; // clear the user's mark
|
|
block->user = NULL; // mark as free
|
|
|
|
other = block->prev;
|
|
if (!other->user)
|
|
{ // merge with previous free block
|
|
other->size += block->size;
|
|
other->next = block->next;
|
|
other->next->prev = other;
|
|
if (block == mainzone->rover)
|
|
mainzone->rover = other;
|
|
else if (block == levelzone->rover)
|
|
levelzone->rover = other;
|
|
block = other;
|
|
}
|
|
|
|
other = block->next;
|
|
if (!other->user)
|
|
{ // merge the next free block onto the end
|
|
block->size += other->size;
|
|
block->next = other->next;
|
|
block->next->prev = block;
|
|
if (other == mainzone->rover)
|
|
mainzone->rover = block;
|
|
else if (other == levelzone->rover)
|
|
levelzone->rover = block;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_Malloc
|
|
=
|
|
= You can pass a NULL user if the tag is < PU_PURGELEVEL
|
|
========================
|
|
*/
|
|
|
|
#if (DEVELOPMENT == 1)
|
|
int totallevelsize=0;
|
|
#endif
|
|
|
|
void *Z_Malloc (int size, int tag, void *user)
|
|
{
|
|
int extra;
|
|
memblock_t *start, *rover, *new, *base;
|
|
|
|
//
|
|
// scan through the block list looking for the first free block
|
|
// of sufficient size, throwing out any purgable blocks along the way
|
|
//
|
|
// size += sizeof(memblock_t); // account for size of block header
|
|
size = (size + sizeof(memblock_t) + 3)&~3; // account for size of block header
|
|
|
|
|
|
//
|
|
// if there is a free block behind the rover, back up over them
|
|
//
|
|
base = mainzone->rover;
|
|
if (!base->prev->user)
|
|
base = base->prev;
|
|
|
|
rover = base;
|
|
start = base->prev;
|
|
|
|
do
|
|
{
|
|
if (rover == start) // scaned all the way around the list
|
|
{
|
|
SoftError("OHSHIT\n");
|
|
Z_DumpHeap(0,200);
|
|
Error ("Z_Malloc: failed on allocation of %i bytes",size);
|
|
}
|
|
if (rover->user)
|
|
{
|
|
if (rover->tag < PU_PURGELEVEL)
|
|
// hit a block that can't be purged, so move base past it
|
|
base = rover = rover->next;
|
|
else
|
|
{
|
|
// free the rover block (adding the size to base)
|
|
base = base->prev; // the rover can be the base block
|
|
Z_Free ((byte *)rover+sizeof(memblock_t));
|
|
base = base->next;
|
|
rover = base->next;
|
|
}
|
|
}
|
|
else
|
|
rover = rover->next;
|
|
} while (base->user || base->size < size);
|
|
|
|
//
|
|
// found a block big enough
|
|
//
|
|
extra = base->size - size;
|
|
if (extra > MINFRAGMENT)
|
|
{ // there will be a free fragment after the allocated block
|
|
new = (memblock_t *) ((byte *)base + size );
|
|
new->size = extra;
|
|
new->user = NULL; // free block
|
|
new->tag = 0;
|
|
new->prev = base;
|
|
new->next = base->next;
|
|
new->next->prev = new;
|
|
base->next = new;
|
|
base->size = size;
|
|
}
|
|
|
|
if (user)
|
|
{
|
|
base->user = user; // mark as an in use block
|
|
*(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
|
|
}
|
|
else
|
|
{
|
|
if (tag >= PU_PURGELEVEL)
|
|
Error ("Z_Malloc: an owner is required for purgable blocks");
|
|
base->user = (void *)2; // mark as in use, but unowned
|
|
}
|
|
base->tag = tag;
|
|
|
|
mainzone->rover = base->next; // next allocation will start looking here
|
|
|
|
|
|
#if (MEMORYCORRUPTIONTEST==1)
|
|
base->posttag=MEMORYPOSTTAG;
|
|
base->pretag=MEMORYPRETAG;
|
|
#endif
|
|
|
|
return (void *) ((byte *)base + sizeof(memblock_t));
|
|
}
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_LevelMalloc
|
|
=
|
|
= Only use this for level structures.
|
|
= You can pass a NULL user if the tag is < PU_PURGELEVEL
|
|
========================
|
|
*/
|
|
|
|
void *Z_LevelMalloc (int size, int tag, void *user)
|
|
{
|
|
int extra;
|
|
memblock_t *start, *rover, *new, *base;
|
|
|
|
//
|
|
// scan through the block list looking for the first free block
|
|
// of sufficient size, throwing out any purgable blocks along the way
|
|
//
|
|
// size += sizeof(memblock_t); // account for size of block header
|
|
size = (size + sizeof(memblock_t) + 3)&~3; // account for size of block header
|
|
|
|
|
|
//
|
|
// if there is a free block behind the rover, back up over them
|
|
//
|
|
base = levelzone->rover;
|
|
if (!base->prev->user)
|
|
base = base->prev;
|
|
|
|
rover = base;
|
|
start = base->prev;
|
|
|
|
do
|
|
{
|
|
if (rover == start) // scaned all the way around the list
|
|
{
|
|
SoftError("OHSHIT\n");
|
|
Z_DumpHeap(0,200);
|
|
Error ("Z_LevelMalloc: failed on allocation of %i bytes",size);
|
|
}
|
|
if (rover->user)
|
|
{
|
|
if (rover->tag < PU_PURGELEVEL)
|
|
// hit a block that can't be purged, so move base past it
|
|
base = rover = rover->next;
|
|
else
|
|
{
|
|
// free the rover block (adding the size to base)
|
|
base = base->prev; // the rover can be the base block
|
|
Z_Free ((byte *)rover+sizeof(memblock_t));
|
|
base = base->next;
|
|
rover = base->next;
|
|
}
|
|
}
|
|
else
|
|
rover = rover->next;
|
|
} while (base->user || base->size < size);
|
|
|
|
//
|
|
// found a block big enough
|
|
//
|
|
extra = base->size - size;
|
|
if (extra > MINFRAGMENT)
|
|
{ // there will be a free fragment after the allocated block
|
|
new = (memblock_t *) ((byte *)base + size );
|
|
new->size = extra;
|
|
new->user = NULL; // free block
|
|
new->tag = 0;
|
|
new->prev = base;
|
|
new->next = base->next;
|
|
new->next->prev = new;
|
|
base->next = new;
|
|
base->size = size;
|
|
}
|
|
|
|
if (user)
|
|
{
|
|
base->user = user; // mark as an in use block
|
|
*(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
|
|
}
|
|
else
|
|
{
|
|
if (tag >= PU_PURGELEVEL)
|
|
Error ("Z_Malloc: an owner is required for purgable blocks");
|
|
base->user = (void *)2; // mark as in use, but unowned
|
|
}
|
|
base->tag = tag;
|
|
|
|
levelzone->rover = base->next; // next allocation will start looking here
|
|
|
|
#if (MEMORYCORRUPTIONTEST==1)
|
|
base->posttag=MEMORYPOSTTAG;
|
|
base->pretag=MEMORYPRETAG;
|
|
#endif
|
|
|
|
return (void *) ((byte *)base + sizeof(memblock_t));
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_FreeTags
|
|
=
|
|
========================
|
|
*/
|
|
|
|
void Z_FreeTags (int lowtag, int hightag)
|
|
{
|
|
memblock_t *block, *next;
|
|
|
|
for (block = mainzone->blocklist.next ; block != &mainzone->blocklist
|
|
; block = next)
|
|
{
|
|
next = block->next; // get link before freeing
|
|
if (!block->user)
|
|
continue; // free block
|
|
if (block->tag >= lowtag && block->tag <= hightag)
|
|
Z_Free ( (byte *)block+sizeof(memblock_t));
|
|
}
|
|
for (block = levelzone->blocklist.next ; block != &levelzone->blocklist
|
|
; block = next)
|
|
{
|
|
next = block->next; // get link before freeing
|
|
if (!block->user)
|
|
continue; // free block
|
|
if (block->tag >= lowtag && block->tag <= hightag)
|
|
Z_Free ( (byte *)block+sizeof(memblock_t));
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_DumpHeap
|
|
=
|
|
========================
|
|
*/
|
|
|
|
void Z_DumpHeap (int lowtag, int hightag)
|
|
{
|
|
memblock_t *block;
|
|
int totalsize;
|
|
|
|
SoftError("MAIN ZONE\n");
|
|
SoftError("zone size: %i location: %p\n",mainzone->size,mainzone);
|
|
SoftError("tag range: %i to %i\n",lowtag, hightag);
|
|
|
|
totalsize=0;
|
|
|
|
for (block = mainzone->blocklist.next ; ; block = block->next)
|
|
{
|
|
if (block->tag >= lowtag && block->tag <= hightag)
|
|
{
|
|
SoftError("block:%p size:%7i user:%p tag:%3i\n",
|
|
block, block->size, block->user, block->tag);
|
|
totalsize+=block->size;
|
|
}
|
|
|
|
if (block->next == &mainzone->blocklist) {
|
|
break; // all blocks have been hit
|
|
}
|
|
if ( (byte *)block + block->size != (byte *)block->next) {
|
|
SoftError("ERROR: block size does not touch the next block\n");
|
|
}
|
|
if ( block->next->prev != block) {
|
|
SoftError("ERROR: next block doesn't have proper back link\n");
|
|
}
|
|
if (!block->user && !block->next->user) {
|
|
SoftError("ERROR: two consecutive free blocks\n");
|
|
}
|
|
}
|
|
SoftError("Total Size of blocks = %d\n",totalsize);
|
|
|
|
SoftError("LEVEL ZONE\n");
|
|
SoftError("zone size: %i location: %p\n",levelzone->size,levelzone);
|
|
SoftError("tag range: %i to %i\n",lowtag, hightag);
|
|
|
|
totalsize=0;
|
|
|
|
for (block = levelzone->blocklist.next ; ; block = block->next)
|
|
{
|
|
if (block->tag >= lowtag && block->tag <= hightag)
|
|
{
|
|
SoftError("block:%p size:%7i user:%p tag:%3i\n",
|
|
block, block->size, block->user, block->tag);
|
|
totalsize+=block->size;
|
|
}
|
|
|
|
if (block->next == &levelzone->blocklist)
|
|
break; // all blocks have been hit
|
|
if ( (byte *)block + block->size != (byte *)block->next) {
|
|
SoftError("ERROR: block size does not touch the next block\n");
|
|
}
|
|
if ( block->next->prev != block) {
|
|
SoftError("ERROR: next block doesn't have proper back link\n");
|
|
}
|
|
if (!block->user && !block->next->user) {
|
|
SoftError("ERROR: two consecutive free blocks\n");
|
|
}
|
|
}
|
|
SoftError("Total Size of blocks = %d\n",totalsize);
|
|
|
|
}
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_UsedHeap
|
|
=
|
|
========================
|
|
*/
|
|
|
|
int Z_UsedHeap ( void )
|
|
{
|
|
memblock_t *block;
|
|
int heapsize;
|
|
|
|
|
|
heapsize=0;
|
|
for (block = mainzone->blocklist.next ; ; block = block->next)
|
|
{
|
|
if ((block->tag>0) && (block->user>(void **)0))
|
|
heapsize+=(block->size);
|
|
if (block->next == &mainzone->blocklist)
|
|
break; // all blocks have been hit
|
|
}
|
|
return heapsize;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_UsedLevelHeap
|
|
=
|
|
========================
|
|
*/
|
|
|
|
int Z_UsedLevelHeap ( void )
|
|
{
|
|
memblock_t *block;
|
|
int heapsize;
|
|
|
|
|
|
heapsize=0;
|
|
for (block = levelzone->blocklist.next ; ; block = block->next)
|
|
{
|
|
if ((block->tag>0) && (block->user>(void **)0))
|
|
heapsize+=(block->size);
|
|
if (block->next == &levelzone->blocklist)
|
|
break; // all blocks have been hit
|
|
}
|
|
return heapsize;
|
|
}
|
|
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_UsedStaticHeap
|
|
=
|
|
========================
|
|
*/
|
|
|
|
int Z_UsedStaticHeap ( void )
|
|
{
|
|
memblock_t *block;
|
|
int heapsize;
|
|
|
|
|
|
heapsize=0;
|
|
for (block = mainzone->blocklist.next ; ; block = block->next)
|
|
{
|
|
if ((block->tag>0) && (block->tag<PU_PURGELEVEL) && (block->user>(void **)0))
|
|
heapsize+=(block->size);
|
|
if (block->next == &mainzone->blocklist)
|
|
break; // all blocks have been hit
|
|
}
|
|
return heapsize;
|
|
}
|
|
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_HeapSize
|
|
=
|
|
========================
|
|
*/
|
|
|
|
int Z_HeapSize ( void )
|
|
{
|
|
return mainzone->size;
|
|
}
|
|
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_CheckHeap
|
|
=
|
|
========================
|
|
*/
|
|
|
|
void Z_CheckHeap (void)
|
|
{
|
|
memblock_t *block;
|
|
|
|
// Check mainzone
|
|
|
|
for (block = mainzone->blocklist.next ; ; block = block->next)
|
|
{
|
|
if (block->next == &mainzone->blocklist)
|
|
break; // all blocks have been hit
|
|
if ( (byte *)block + block->size != (byte *)block->next)
|
|
Error ("Z_CheckHeap: block size does not touch the next block\n");
|
|
if ( block->next->prev != block)
|
|
Error ("Z_CheckHeap: next block doesn't have proper back link\n");
|
|
if (!block->user && !block->next->user)
|
|
Error ("Z_CheckHeap: two consecutive free blocks\n");
|
|
#if (MEMORYCORRUPTIONTEST==1)
|
|
if ((block->tag>0) && (block->user>0))
|
|
{
|
|
if (block->posttag!=MEMORYPOSTTAG)
|
|
Error("Z_CheckHeap: Corrupted posttag\n");
|
|
if (block->pretag!=MEMORYPRETAG)
|
|
Error("Z_CheckHeap: Corrupted pretag\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Check levelzone
|
|
|
|
for (block = levelzone->blocklist.next ; ; block = block->next)
|
|
{
|
|
if (block->next == &levelzone->blocklist)
|
|
break; // all blocks have been hit
|
|
if ( (byte *)block + block->size != (byte *)block->next)
|
|
Error ("Z_CheckHeap: block size does not touch the next block\n");
|
|
if ( block->next->prev != block)
|
|
Error ("Z_CheckHeap: next block doesn't have proper back link\n");
|
|
if (!block->user && !block->next->user)
|
|
Error ("Z_CheckHeap: two consecutive free blocks\n");
|
|
#if (MEMORYCORRUPTIONTEST==1)
|
|
if ((block->tag>0) && (block->user>0))
|
|
{
|
|
if (block->posttag!=MEMORYPOSTTAG)
|
|
Error("Z_CheckHeap: Corrupted posttag\n");
|
|
if (block->pretag!=MEMORYPRETAG)
|
|
Error("Z_CheckHeap: Corrupted pretag\n");
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_ChangeTag
|
|
=
|
|
========================
|
|
*/
|
|
|
|
void Z_ChangeTag (void *ptr, int tag)
|
|
{
|
|
memblock_t *block;
|
|
|
|
block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
|
|
block->tag = tag;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_AvailHeap
|
|
=
|
|
========================
|
|
*/
|
|
|
|
int Z_AvailHeap ( void )
|
|
{
|
|
#ifdef DOS
|
|
union REGS zregs;
|
|
struct SREGS zsregs;
|
|
|
|
|
|
zregs.x.eax = 0x00000500;
|
|
memset( &zsregs, 0, sizeof(zsregs) );
|
|
zsregs.es = FP_SEG( &MemInfo );
|
|
zregs.x.edi = FP_OFF( &MemInfo );
|
|
|
|
int386x( DPMI_INT, &zregs, &zregs, &zsregs );
|
|
|
|
return ((int)MemInfo.LargestBlockAvail);
|
|
#else
|
|
return MAXMEMORYSIZE;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
========================
|
|
=
|
|
= Z_Realloc
|
|
=
|
|
========================
|
|
*/
|
|
|
|
void Z_Realloc (void ** ptr, int newsize)
|
|
{
|
|
memblock_t *block;
|
|
void * newptr;
|
|
int oldsize;
|
|
|
|
block = (memblock_t *) ( (byte *)(*ptr) - sizeof(memblock_t));
|
|
oldsize = block->size;
|
|
newptr = SafeMalloc(newsize);
|
|
if (oldsize > newsize)
|
|
{
|
|
oldsize = newsize;
|
|
}
|
|
memcpy( newptr, *ptr, oldsize );
|
|
SafeFree( *ptr );
|
|
*ptr = newptr;
|
|
}
|
|
|