#include <linux/types.h>
#include <errno.h>
#include <unistd.h>

void * ___brk_addr = NULL;
static void set_brk_addr(void);

/*
 *  Set the current location for the break address.
 */

#ifdef ELF_LIBRARY
#define __sbrk _sbrk
#define __brk _brk
#endif

#if defined(COFF_LIBRARY)
#include <ibcs/unistd.h>
#include <sysdeps.h>

static void set_brk_addr(void)
    {
    void * value = NULL;

    __asm__ ("xor\t%%edx,%%edx\n\t"
	     "pushl\t%%edx\n\t"
	     "pushl\t%%edx\n\t"
	     ".byte\t0x9a,0,0,0,0,7,0\n\t"
	     "jnc\t1f\n\t"
	     "xor\t%%eax,%%eax\n"
	     "1:\n\t"
	     "addl\t$8,%%esp\n\t"
	     : "=a" (value) : "0" (__IBCS_brk));

    ___brk_addr = value;
    }

#else
static void set_brk_addr(void)
    {
    int saved_errno = errno;
    (void) __brk (NULL);

    errno = saved_errno;
    }
#endif

/*
 *  Adjust the break address by some delta value.
 */

void *__sbrk(ptrdiff_t increment)
    {
    void * tmp = ___brk_addr;
    void * target;
/*
 *  If the break address is unknown, then ask the operating system.
 */
    if (___brk_addr == NULL)
        {
	set_brk_addr();
        }
/*
 *  Update the break address with the increment value.
 */
    target = ___brk_addr + increment;
    __brk (target);
/*
 *  If the break address is invalid then indicate the failure.
 */    
    if (___brk_addr != target)
        {
	errno = ENOMEM;
	tmp   = (void *) -1;
        }
/*
 *  Return the pointer to the new memory block.
 */
    return tmp;
    }

#ifdef ELF_LIBRARY
__asm__(".weak sbrk; sbrk = _sbrk");
#endif
