Some alloc/free implementation: The FARmalloc / FARfree
will probably work, but the NEAR versions are a bad idea
by design. Just an example of doing -anything- NEAR here.

Note on near pointer alloc/free: it would be a lot better
to just set the heap size in the exe pointer to have 64k
of near data segment always allocated. Then near malloc /
free would - without using int 21 - keep track of which
areas of the data segment are in use. For example you can
have a global near "start" pointer, a global near "end of
used area" pointer, and code which handles area headers
consisting of "pointer to next area" and "byte with flags
indicating whether the area is in use". Freeing an area
which ends at "end of used area" should cause an update
of the "end of used area" pointer. Allocating more data
than the biggest used area will move the "end" pointer if
possible and will fail if the pointer is too big (more
than 64k, or if the stack is at the end of the 64k, after
the point where the stack starts). Check Tom's talloc
system which is used in some Kitten versions.

---- dallcmem.c ----

#include <dos.h>
#include <errno.h>

/* allocate N*16 bytes of DOS RAM, return the segment
 * or, on error, the errorcode (less than 16). On error
 * (carry set), BX would be the max okay alloc size) */
unsigned __doalloc( unsigned size );
#pragma aux __doalloc = \
    "mov bx, ax"	\
    "mov ah, 0x48"      \
    "int 0x21"          \
    parm [ax]           \
    value [ax]          \
    modify [bx];

unsigned _dos_allocmem( unsigned size, unsigned *seg ) {
    register unsigned retval = __doalloc( size );
    if ( retval < 16 ) {
        errno = ENOMEM;
        _doserrno = retval;
        return retval; /* return nonzero on error */
    }
    *seg = retval;
    return 0;
}

---- end of dallcmem.c ----

#include <dos.h>
#include <malloc.h>
static unsigned __malloc_ds = 0;

void far *farmalloc( size_t bytes ) { /* far pointer version */
    unsigned segm; /* must not be a register */
    void far * where;
    if ( _dos_allocmem( bytes, &segm ) != 0 ) return NULL;
    where = MK_FP(segm, 0); /* or segm+1? what does int 21.48 return? */
    return where;
}

void *malloc( size_t bytes ) { /* near pointer version */
    void far * where = farmalloc( bytes );
    if ( where == NULL ) return NULL;
    if ( __malloc_ds == 0 ) { /* *** do sth which REALLY finds our DS */ }
    if ( ( segm < __malloc_ds ) || ( segm > (__malloc_ds+0xfff) ) ) {
        /* Can't be a near pointer */
        farfree( where );
        return NULL;
    }
    return (unsigned) ((segm - __malloc_ds) << 4);
}

void farfree( void far *buf ) { /* far pointer version */
    if ( FP_OFF(buf) != 0 ) return; /* and set some error flag */
    _dos_freemem( FP_SEG(buf) ); /* or FP_SEG(buf)-1 ? */
}

void free( void *buf ) { /* near pointer version */
    unsigned offs = (unsigned)buf;
    void far * where = MK_FP( __malloc_ds + (offs >> 4), offs & 15 );
    farfree( where );
}

