home *** CD-ROM | disk | FTP | other *** search
- /*
- #### # # # #
- # # # # # The FreeWare C library for
- # # ## ### # # # # ### RISC OS machines
- # # # # # # # # # # # ___________________________________
- # # #### ### ## # # # #
- # # # # # # # # # # Please refer to the accompanying
- #### ### #### # # ##### # ### documentation for conditions of use
- ________________________________________________________________________
-
- File: Mem.MidExtend.c
- Author: Copyright © 1993 Jason Williams
- Version: 1.00 (12 May 1993)
- Purpose: Dynamic memory manager - reallocation
- */
-
- #include "MemDefs.h"
-
- #include <string.h>
-
-
- extern BOOL Mem_MidExtend(mem_anchor *anchor, int at, int by)
- /* Enlarges or reduces a Mem chunk by moving all data beyond 'at' by
- * 'by' bytes up or down in memory. 'at' is an offset within the chunk.
- *
- * Goes to rather a lot of effort to avoid moving the base address of
- * this chunk and others, but if mem_autocompact allows, it will compact
- * if it is absolutely necessary in order to manage the extension.
- *
- * Returns TRUE if it succeeds
- */
- {
- mem_header *chunk, *next, *prev;
- mem_anchor newchunk;
- int needed;
- char *database;
-
- if (by == 0 || at < 0 || !Mem__FindChunk(anchor, &chunk)) return(FALSE);
- if (at > chunk->datasize) return(FALSE);
-
- database = ((char *) chunk) + sizeof(mem_header);
-
-
- /* ------ Reduce chunk ------ */
- if (by < 0) /* Reducing the size of the chunk */
- {
- if (-by > at) by = -at; /* Can't delete past start of chunk */
-
- memmove(database + at + by, database + at, chunk->datasize - at);
- chunk->datasize += by; /* Shrink data area of this block */
-
- Mem__SplitOffFreeChunk(chunk); /* Return any free space for use */
- /* The anchor has not changed */
- return(TRUE);
- }
-
-
- /* ------ Extend chunk ------ */
- if ((int) chunk > (int) mem__heap) /* Step 1: merge with prevchunk if free */
- {
- prev = Mem__PrevChunk(chunk);
- if (ISFREE(prev))
- {
- int newsize = prev->realsize + chunk->realsize;
-
- /* Merge this chunk into the previous (free) chunk, shifting the data
- * down into it.
- */
- memmove((void *) prev, (void *) chunk, chunk->realsize);
- prev->realsize = newsize;
-
- if (chunk == mem__lastchunk)
- mem__lastchunk = prev;
- else
- {
- next = Mem__NextChunk(prev);
- next->prevrealsize = newsize;
- }
- chunk = prev;
- *anchor = (mem_anchor) ((int)chunk + sizeof(mem_header));
- }
- }
-
-
- if (chunk != mem__lastchunk) /* Step 2: merge with next chunk if free */
- {
- next = Mem__NextChunk(chunk);
- if (ISFREE(next))
- {
- /* Next chunk is free, so we merge it onto the end of this one */
-
- chunk->realsize += next->realsize;
- if (next == mem__lastchunk)
- mem__lastchunk = chunk;
- else
- {
- next = Mem__NextChunk(chunk);
- next->prevrealsize = chunk->realsize;
- }
- }
- }
-
-
- /* Step 3: Allocate more heap space if this is last chunk */
- needed = chunk->datasize + by + sizeof(mem_header);
- if (chunk == mem__lastchunk && chunk->realsize < needed)
- {
- /* Still too small? This is the last chunk in the heap, so just
- * extend the heap to make enough room. Note that normally we won't
- * have data in the last chunk, but the previous 2 steps may have
- * merged another chunk into the last (free) chunk to try to get
- * enough memory.
- */
- mem__heapsize = Mem__HeapSize(mem__heapsize + 16 +
- (needed - chunk->realsize));
- mem__lastchunk->realsize = mem__heap + mem__heapsize - (int)mem__lastchunk;
- }
-
-
- /* Now, is the resulting chunk big enough to hold the extended data? */
- if (chunk->realsize >= needed)
- {
- memmove(database + at + by, database + at, chunk->datasize - at);
- chunk->datasize += by; /* Expand data area of this block */
-
- Mem__SplitOffFreeChunk(chunk); /* Return any free space for use */
-
- /* The anchor has not changed */
- return(TRUE);
- }
-
- Mem__SplitOffFreeChunk(chunk); /* Return any free space for use */
-
- /* Still unable to extend the chunk.
- * Check if we can relocate this chunk into a larger one, compacting
- * if necessary (but only if we are allowed to by mem_autocompact)
- */
-
- Mem_Alloc(&newchunk, chunk->datasize + by);
- if (newchunk == NULL)
- {
- /* **** Exercise for the reader
- * We can't just grab another chunk of large enough size.
- * At this point, we really should (if allowed) compact the
- * heap, extend the heap if necessary, then shift everything
- * above 'chunk' up enough to extend the chunk as needed.
- * However, this takes a bit of effort on my part, and also will
- * add a large bit of code to this function, so I have not yet
- * implemented it
- */
-
- return(FALSE);
- }
-
- memmove((char *) newchunk, database, at); /* Copy 1st part of data */
- memmove((char *) ((int) newchunk) + at + by, /* Copy 2nd part of data */
- database + at, chunk->datasize - at);
-
- Mem_Free(anchor);
- *anchor = newchunk;
- Mem__FindChunk(&newchunk, &chunk);
- chunk->handle = anchor;
-
- return(TRUE);
- }
-