#include <stdio.h>
#include <stdlib.h>
#include <dos.h>


void far *aligned_malloc(long len)
{
       void far *ptr;
       unsigned int far *orig_ptr;
       unsigned seg, orig_seg, orig_off;
       long lin_addr;

       /* Allocate double the required space */

       if(allocmem((len * 2L + 32L + 15L) >> 4, &seg) != -1)
               return NULL;

       /* Compute a new pointer to the buffer such that the next "len" bytes */
       /* do not cross a page boundary, and the offset is zero */
       /* (as required by DMA transfers) */
       orig_off = 0;
       orig_seg = seg;
       /* reserve 4 bytes for the original pointer */
       lin_addr = (orig_seg * 16L) + orig_off + 4L;
       if((lin_addr & 0xF0000L) != ((lin_addr+len-1) & 0xF0000L))
               lin_addr = (lin_addr+len-1)&0xF0000L;
       else
               lin_addr = (lin_addr+15) & 0xFFFF0L;

       seg = (unsigned int)(lin_addr/16);
       orig_ptr = (unsigned far *)MK_FP(seg-1,0x000C);
       orig_ptr[0] = orig_off;
       orig_ptr[1] = orig_seg;
       ptr = MK_FP(seg, 0);

/*
       printf("Original: %04x:%04x, New: %04x:%04x, Linear: %05lx\n",
       orig_seg,orig_off,FP_SEG(ptr),FP_OFF(ptr),lin_addr);
*/

       return ptr;
}


void aligned_free(void far *ptr)
{
       if(ptr!=NULL) {
               unsigned far *old_ptr=(unsigned far *)MK_FP(FP_SEG(ptr)-1,0x000c);
     /*
        printf("Freeing: %04x:%04x, Ptr: %04x:%04x\n",
        FP_SEG(old_ptr),FP_OFF(old_ptr),FP_SEG(ptr),FP_OFF(ptr));
        */
               farfree(MK_FP(old_ptr[1],old_ptr[0]));
       }
}