mirror of
https://github.com/cc65/cc65.git
synced 2024-09-11 22:55:11 +00:00
Change the isxxx functions to correctly handle values outside of character range. git-svn-id: svn://svn.cc65.org/cc65/trunk@33 b7a2c559-68d2-44c3-8de9-860c34a00d81
111 lines
2.7 KiB
C
111 lines
2.7 KiB
C
/*
|
|
* malloc.c
|
|
*
|
|
* Ullrich von Bassewitz, 03.06.1998
|
|
*/
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
#include "_heap.h"
|
|
|
|
|
|
|
|
void* malloc (size_t size)
|
|
/* Allocate memory from the given heap. The function returns a pointer to the
|
|
* allocated memory block or a NULL pointer if not enough memory is available.
|
|
* Allocating a zero size block is not allowed.
|
|
*/
|
|
{
|
|
struct freeblock* f;
|
|
unsigned* p;
|
|
|
|
|
|
/* Check for a size of zero, then add the administration space and round
|
|
* up the size if needed.
|
|
*/
|
|
if (size == 0) {
|
|
return 0;
|
|
}
|
|
size += HEAP_ADMIN_SPACE;
|
|
if (size < sizeof (struct freeblock)) {
|
|
size = sizeof (struct freeblock);
|
|
}
|
|
|
|
/* Search the freelist for a block that is big enough */
|
|
f = _hfirst;
|
|
while (f && f->size < size) {
|
|
f = f->next;
|
|
}
|
|
|
|
/* Did we find one? */
|
|
if (f) {
|
|
|
|
/* We found a block big enough. If the block can hold just the
|
|
* requested size, use the block in full. Beware: When slicing blocks,
|
|
* there must be space enough to create a new one! If this is not the
|
|
* case, then use the complete block.
|
|
*/
|
|
if (f->size - size < sizeof (struct freeblock)) {
|
|
|
|
/* Use the actual size */
|
|
size = f->size;
|
|
|
|
/* Remove the block from the free list */
|
|
if (f->prev) {
|
|
/* We have a previous block */
|
|
f->prev->next = f->next;
|
|
} else {
|
|
/* This is the first block, correct the freelist pointer */
|
|
_hfirst = f->next;
|
|
}
|
|
if (f->next) {
|
|
/* We have a next block */
|
|
f->next->prev = f->prev;
|
|
} else {
|
|
/* This is the last block, correct the freelist pointer */
|
|
_hlast = f->prev;
|
|
}
|
|
|
|
} else {
|
|
|
|
/* We must slice the block found. Cut off space from the upper
|
|
* end, so we can leave the actual free block chain intact.
|
|
*/
|
|
|
|
/* Decrement the size of the block */
|
|
f->size -= size;
|
|
|
|
/* Set f to the now unused space above the current block */
|
|
f = (struct freeblock*) (((unsigned) f) + f->size);
|
|
|
|
}
|
|
|
|
/* Setup the pointer for the block */
|
|
p = (unsigned*) f;
|
|
|
|
} else {
|
|
|
|
/* We did not find a block big enough. Try to use new space from the
|
|
* heap top.
|
|
*/
|
|
if (((unsigned) _hend) - ((unsigned) _hptr) < size) {
|
|
/* Out of heap space */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* There is enough space left, take it from the heap top */
|
|
p = _hptr;
|
|
_hptr = (unsigned*) (((unsigned) _hptr) + size);
|
|
|
|
}
|
|
|
|
/* New block is now in p. Fill in the size and return the user pointer */
|
|
*p++ = size;
|
|
return p;
|
|
}
|
|
|
|
|
|
|