This file contains 3 files: xmem.h : c include file xmem.asm : low level basic XMS acess xmemc.c : super easy C access via functions like fopen, fread, fwrite xopen, xread, xwrite, xseek etc... FOR DOS REAL mode programs, requires HIMEM.SYS to be loaded in config.sys. XMEM.H ------------- START -------------------------------------------------- #if !defined(_XMEM_H) #define _XMEM_H typedef struct xms_node { long start, size, off; short used; struct xms_node *next; } xms_node_t; typedef struct { int handle; unsigned long total; unsigned long avail; unsigned long next_off; xms_node_t *next; } xms_head_t; #define XMSBLOCK 16384u #define XMSBLOCKSHIFT 14 extern void LSHL( unsigned long far *SHLnumber, unsigned short n ); extern unsigned short XMS_available( void ); extern unsigned short XMSblk_available( void ); extern short XMS_alloc(unsigned short rsrvd, unsigned short far *size ); extern short XMS_dealloc(unsigned short Hdl ); extern short XMStoMem(unsigned short Handle, // XMS handle returned by XMS_alloc() unsigned short blk, // which 16k block to copy to unsigned short blkAdr, // offset within 16k block unsigned short Bytes, // bytes to copy void far *memAdr ); extern short MemToXMS(unsigned short Handle, unsigned short blk, unsigned short blkAdr, unsigned short Bytes, void far *memAdr ); // call these for ease short alloc_xms(unsigned short far *size); // size in 16k blocks // NOTE size is changed to the amount block size was altered by! // normaly this is zero short xms_to_mem(unsigned short handle, void far *p, unsigned long off, unsigned short n); short mem_to_xms(unsigned short handle, void far *p, unsigned long off, unsigned short n); void deinit_xms(void); short init_xms(unsigned short min_blocks); void qfree_xms(xms_node_t *node); xms_node_t *qalloc_xms(unsigned long size); xms_node_t *xms_open(char *file); short xms_read(void far *buffer, unsigned short n, xms_node_t *node); short xms_write(void far *buffer, unsigned short n, xms_node_t *node); long xms_tell(xms_node_t *node); short xms_seek(xms_node_t *node, long off, short whence); void xms_close(xms_node_t *node); extern xms_head_t xms_head; #endif /* ---------------------------------- end of file --------------------- */ XMEM.H ------------- END -------------------------------------------------- xmem.asm --------------------- START -------------------------------------- ;----------------------------------------------------------------------- ; .MODEL MEDIUM EXTmemError EQU 7 XMSmemError EQU 8 ShortAdr EQU 0 LongAdr EQU 1 procname MACRO Pnam PUBLIC _&Pnam& _&Pnam& PROC FAR ENDM endproc MACRO Pnam _&Pnam& ENDP ENDM pwrlolvl_TEXT SEGMENT WORD PUBLIC 'CODE' ASSUME CS:pwrlolvl_TEXT, DS:pwrlolvl_TEXT, ES:pwrlolvl_TEXT SUBTTL (Local Procedure) XMS_setup - find a XMS driver. PAGE+ EVEN XMSwordByte LABEL BYTE XMSword DW 0 XMSmoveSTRUC STRUC Length DW 0 LengthX DW 0 SrcHandle DW 0 SrcOffset DW 0 SrcOffsetX DW 0 DestHandle DW 0 DestOffset DW 0 DestOffsetX DW 0 XMSmoveSTRUC ENDS XMSmainGET XMSmoveSTRUC <> XMSmainPUT XMSmoveSTRUC <> XMSwordGET XMSmoveSTRUC <2,,,,,,OFFSET XMSword> XMSwordPUT XMSmoveSTRUC <2,,,OFFSET XMSword> XMSfunctAdr DW 0, 0 ; Don't try to call this from your programs XMS_setup PROC NEAR PUSH DS PUSH ES PUSH BX MOV AX,CS ; Set Data segment to the code segment. MOV DS,AX ; MOV [XMSwordGET.DestOffsetX],AX ; Set up the move data structures. MOV [XMSwordPUT.SrcOffsetX],AX ; MOV AX,4300H ; See if a XMS Driver Exists. INT 2FH ; CMP AL,80H ; MOV AX,0 ; JNE XMS_setup01 ; Return 0 if not. MOV AX,4310H ; If so, set the driver's function INT 2FH ; address. MOV [XMSfunctAdr],BX ; MOV [XMSfunctAdr+2],ES ; MOV AX,1 ; Return 1. XMS_setup01: POP BX POP ES POP DS RET XMS_setup ENDP SUBTTL LSHL - Shift an unsigned long left PAGE+ ;**************************************************************************** ;* ;* Shift an unsigned long integer left n number of bits. ;* ;**************************************************************************** ; ; Stack frame definition for void LSHL( unsigned long *SHLnumber, unsigned n ); ; LSHLparms STRUC DW 0, 0 DW 0 SHLadr DD ? SHLn DW ? LSHLparms ENDS procname LSHL PUSH BP MOV BP,SP PUSH BX PUSH CX PUSH DX PUSH DS LDS BX,SHLadr[BP] MOV CX,SHLn[BP] MOV AX,[BX] ; Get the long integer. MOV DX,[BX+2] ; LSHL_01: SHL AX,1 ; Do the long shift. RCL DX,1 ; LOOP LSHL_01 ; MOV [BX],AX ; Replace the addressed number. MOV [BX+2],DX ; POP DS POP DX POP CX POP BX POP BP RET ; Exit endproc LSHL SUBTTL Extended Memory - Stack template for EXTget, EXTput PAGE+ EXTgpparms STRUC DW 0, 0 DW 0 extgpBase DW ? extgpblk DW ? extgpblkAdr DW ? extgpBytes DW ? extgpmemAdr DW ? DW ? EXTgpparms ENDS SUBTTL Extended Memory - XMS - Return total XMS memory. PAGE+ ; Use this function to detect wether or not XMS driver installed ; ; Stack frame definition for unsigned XMS_available( void ); ; ; The total XMS memory available (in 16k blocks) is returned. ; procname XMS_available PUSH BX PUSH CX PUSH DX CALL XMS_setup ; Ensure XMS memory is set. TEST AX,AX ; JZ XMS_available01 ; Return zero if not. MOV AH,08H ; Set the size function code. CALL DWORD PTR CS:[XMSfunctAdr] ; Get the size. TEST AX,AX ; JZ XMS_available01 ; MOV AX,DX ; Set available Kbytes. SUB AX,64 ; Subtract out the HMA (HIMEM.SYS bug). JNC XMS_available01 ; XOR AX,AX ; Set zero if underflow. XMS_available01: MOV CL,4 ; Divide Kbytes by 16 for blocks. SHR AX,CL ; POP DX POP CX POP BX RET ; Exit endproc XMS_available SUBTTL Extended Memory - XMS - Return largest block XMS mem. PAGE+ ; ; Stack frame definition for unsigned XMSblk_available( void ); ; ; The size of the largest block of XMS memory available, ; (in 16Kbyte blocks) is returned. ; procname XMSblk_available PUSH BX PUSH CX PUSH DX CALL XMS_setup ; Ensure XMS memory is set. TEST AX,AX ; JZ XMSblk_available01 ; Return zero if not. MOV AH,08H ; Set the size function code. CALL DWORD PTR CS:[XMSfunctAdr] ; Get the size. TEST AX,AX ; JZ XMSblk_available01 ; SUB DX,64 ; Subtract out the HMA (HIMEM.SYS bug). JNC XMSblk_available0X ; XOR DX,DX ; Set zero if underflow. XMSblk_available0X: CMP AX,DX ; JBE XMSblk_available01 ; MOV AX,DX ; Set available Kbytes. XMSblk_available01: MOV CL,4 ; Divide Kbytes by 16 for blocks. SHR AX,CL ; POP DX POP CX POP BX RET ; Exit endproc XMSblk_available SUBTTL Extended Memory - XMS De-allocate a memory block. PAGE+ ; ; Stack frame definition for int XMS_dealloc( int Hdl ); ; ; Zero is returned if the operation fails, non-zero if success. ; ; its really important to do this, only other way to recover ; XMS blocks is to re-boot XMSdealparms STRUC DW 0, 0 DW 0 xmsdealHdl DW ? XMSdealparms ENDS procname XMS_dealloc PUSH BP MOV BP,SP PUSH BX PUSH DX ; CALL XMS_setup ; Ensure XMS memory is set. ; TEST AX,AX ; ; JZ XMS_dealloc01 ; Return zero if not. MOV DX,xmsdealHdl[BP] ; Get the handle to de-allocate. MOV AH,0AH ; CALL DWORD PTR CS:[XMSfunctAdr] ; De-allocate it. XMS_dealloc01: POP DX POP BX POP BP RET ; Exit endproc XMS_dealloc SUBTTL Extended Memory - XMS Allocate a memory block. PAGE+ ; ; Stack frame definition for int XMS_alloc( unsigned rsrvd, *size ); ; ; rsrved and size are in 16K byte blocks. ; rsrved is mem set aside for EMS, generaly zero ; ; Zero is returned if the operation fails. ; Block (XMS) handle is returned if success. ; ; size - is reduced by the amount of XMS memory actually allocated. ; XMSalparms STRUC DW 0, 0 DW 0 xmsalrsrvd DW ? xmsalsize DD ? XMSalparms ENDS procname XMS_alloc PUSH BP MOV BP,SP PUSH BX PUSH CX PUSH DX PUSH DI PUSH ES PUSH DS MOV AX,CS ; Set the data segment to the code MOV DS,AX ; segment. MOV CX,4 ; ADD xmsalrsrvd[BP],CX ; Subtract out the HMA (HIMEM.SYS bug). SHL xmsalrsrvd[BP],CL ; Convert reserved blocks to K-bytes. LES DI,xmsalsize[BP] ; Load size address. XOR AX,AX ; MOV BX,ES:[DI] ; Get the requested size in blocks. TEST BX,0F000H ; Check for more than 64 Megabytes. JZ XMS_alloc01 ; MOV BX,00FFFH ; XMS_alloc01: MOV CL,4 ; SHL BX,CL ; Convert to K-Bytes. MOV CX,BX ; In CX. JZ XMS_alloc05 ; Return zero if no size requested. ; CALL XMS_setup ; Ensure XMS memory is set. ; TEST AX,AX ; ; JZ XMS_alloc05 ; Return zero if not. XOR BX,BX ; MOV AH,08H ; Set to Query Free XMS Memory. CALL DWORD PTR [XMSfunctAdr] ; SUB DX,xmsalrsrvd[BP] ; Subtract out reserved blocks. JB XMS_alloc03 ; Ensure no borrow. CMP AX,DX ; JBE XMS_alloc02 ; MOV AX,DX ; XMS_alloc02: MOV DX,AX ; CMP AX,68 ; Ensure enough memory to allocate. XMS_alloc03: MOV AX,0 ; JB XMS_alloc05 ; Exit if not. CMP BL,80H ; Check for errors. JE XMS_alloc05 ; CMP BL,81H ; JE XMS_alloc05 ; CMP CX,DX ; Check actual against requested size. JBE XMS_alloc04 ; MOV CX,DX ; Set if actual < requested. XMS_alloc04: MOV DX,CX ; Set requested size. MOV AH,09H ; CALL DWORD PTR [XMSfunctAdr] ; Allocate it. DEC AX ; Check for errors. MOV AX,0 ; JNZ XMS_alloc05 ; MOV AX,CX ; Convert allocated size in KBytes MOV CL,4 ; to allocated blocks. SHR AX,CL ; SUB ES:[DI],AX ; Subtract the blocks allocated. MOV AX,DX ; Set to return the handle. XMS_alloc05: POP DS POP ES POP DI POP DX POP CX POP BX POP BP RET ; Exit endproc XMS_alloc SUBTTL Extended Memory - XMS get, put Stack Frame definition PAGE+ XMSgpparms STRUC DW 0, 0 DW 0 xmsgpHdl DW ? xmsgpblk DW ? xmsgpblkAdr DW ? xmsgpBytes DW ? xmsgpmemAdr DD ? XMSgpparms ENDS SUBTTL Extended Memory - XMStoMem PAGE+ ; ; Stack frame definition for int XMStoMem( unsigned Handle, ; unsigned blk, ; unsigned blkAdr, ; unsigned Bytes, ; char *memAdr ; ); ; ; XMSmemError is returned if the operation fails, Zero if success. ; procname XMStoMem PUSH BP MOV BP,SP PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI PUSH ES PUSH DS MOV AX,CS ; Set Data Segment to Code Segment. MOV DS,AX ; MOV CX,xmsgpBytes[BP] ; Get the number of bytes to transfer. LES BX,xmsgpmemAdr[BP] ; Get the memory address. MOV DX,xmsgpHdl[BP] ; Get the XMS handle. MOV [XMSmainGET.SrcHandle],DX ; Set it in the move structures. MOV [XMSwordGET.SrcHandle],DX ; XOR DX,DX ; MOV DI,xmsgpblk[BP] ; Get the block number. SHR DI,1 ; Form the 32 bit XMS address in RCR DX,1 ; DI:DX. SHR DI,1 ; RCR DX,1 ; ADD DX,xmsgpblkAdr[BP] ; TEST CX,1 ; Check for an odd number of bytes JZ XMStoMem02 ; to transfer. DEC CX ; Decrement to an even number of bytes. TEST DX,1 ; Check for an odd XMS address. JZ XMStoMem01 ; ; XMS address is odd. ; ------------------- DEC DX ; MOV [XMSwordGET.SrcOffset],DX ; Set the XMS address. MOV [XMSwordGET.SrcOffsetX],DI ; MOV AH,0BH ; Set the XMS move, function code. MOV SI,OFFSET XMSwordGET ; Set address of the move structure. PUSH BX ; CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler. POP BX ; DEC AX ; Check for errors. JNZ XMStoMem03 ; Error out if error. MOV AX,[XMSword] ; Get the moved word. MOV ES:[BX],AH ; Move the odd byte to memory. INC BX ; Reset the memory address. ADD DX,2 ; And the XMS address. JMP XMStoMem02 ; Move the block. XMStoMem01: ; XMS address is even. ; -------------------- ADD DX,CX ; MOV [XMSwordGET.SrcOffset],DX ; Set the XMS address. SUB DX,CX ; MOV [XMSwordGET.SrcOffsetX],DI ; MOV AH,0BH ; Set the XMS move, function code. MOV SI,OFFSET XMSwordGET ; Set address of the move structure. PUSH BX ; CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler. POP BX ; DEC AX ; Check for errors. JNZ XMStoMem03 ; Error out if error. MOV AX,[XMSword] ; Get the moved word. XCHG DI,CX ; MOV ES:[BX+DI],AL ; Move the odd byte to memory. XCHG DI,CX ; XMStoMem02: JCXZ XMStoMem04 ; Avoid a zero byte move. MOV XMSmainGET.Length,CX ; Set length for the move. MOV XMSmainGET.DestOffset,BX ; Set Memory address. MOV XMSmainGET.DestOffsetX,ES ; MOV XMSmainGET.SrcOffset,DX ; Set XMS address. MOV XMSmainGET.SrcOffsetX,DI ; MOV AH,0BH ; Set the XMS move, function code. MOV SI,OFFSET XMSmainGET ; Set address of the move structure. CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler. DEC AX ; Check for errors. JZ XMStoMem05 XMStoMem03: MOV AX,XMSmemError ; Set error code if error. JMP XMStoMem05 ; XMStoMem04: XOR AX,AX ; XMStoMem05: POP DS POP ES POP DI POP SI POP DX POP CX POP BX POP BP RET ; Exit endproc XMStoMem SUBTTL Extended Memory - MemToXMS PAGE+ ; ; Stack frame definition for int MemToXMS( unsigned Handle, ; unsigned blk, ; unsigned blkAdr, ; unsigned Bytes, ; char *memAdr ; ); ; ; XMSmemError is returned if the operation fails, Zero if success. ; procname MemToXMS PUSH BP MOV BP,SP PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI PUSH ES PUSH DS MOV AX,CS ; MOV DS,AX ; MOV CX,xmsgpBytes[BP] ; Get the number of bytes to transfer. LES BX,xmsgpmemAdr[BP] ; Get the memory address. MOV DX,xmsgpHdl[BP] ; Get the XMS handle. MOV [XMSmainPUT.DestHandle],DX ; Set it in the move structures. MOV [XMSwordPUT.DestHandle],DX ; MOV [XMSwordGET.SrcHandle],DX ; XOR DX,DX ; MOV DI,xmsgpblk[BP] ; Get the block number. SHR DI,1 ; Form the 32 bit XMS address in RCR DX,1 ; DI:DX. SHR DI,1 ; RCR DX,1 ; ADD DX,xmsgpblkAdr[BP] ; TEST CX,1 ; Check for an odd number of bytes JZ MemToXMS02 ; to transfer. DEC CX ; Decrement to an even number of bytes. TEST DX,1 ; Check for an odd XMS address. JZ MemToXMS01 ; ; XMS address is odd. ; ------------------- DEC DX ; MOV [XMSwordGET.SrcOffset],DX ; Set the XMS address. MOV [XMSwordGET.SrcOffsetX],DI ; MOV [XMSwordPUT.DestOffset],DX ; MOV [XMSwordPUT.DestOffsetX],DI ; MOV AH,0BH ; Set the XMS move, function code. MOV SI,OFFSET XMSwordGET ; Set address of the move structure. PUSH BX ; CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler. POP BX ; DEC AX ; Check for errors. JNZ MemToXMS03 ; Error out if error. MOV AH,ES:[BX] ; Get the odd memory byte. MOV [XMSwordByte+1],AH ; Put it in the moved word. MOV AH,0BH ; Set the XMS move, function code. MOV SI,OFFSET XMSwordPUT ; Set address of the move structure. PUSH BX ; CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler. POP BX ; DEC AX ; Check for errors. JNZ MemToXMS03 ; Error out if error. INC BX ; Reset the memory address. ADD DX,2 ; And the XMS address. JMP MemToXMS02 ; Move the block. MemToXMS01: ; XMS address is even. ; -------------------- ADD DX,CX ; MOV [XMSwordGET.SrcOffset],DX ; Set the XMS address. MOV [XMSwordPUT.DestOffset],DX ; SUB DX,CX ; MOV [XMSwordGET.SrcOffsetX],DI ; MOV [XMSwordPUT.DestOffsetX],DI ; MOV AH,0BH ; Set the XMS move, function code. MOV SI,OFFSET XMSwordGET ; Set address of the move structure. PUSH BX ; CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler. POP BX ; DEC AX ; Check for errors. JNZ MemToXMS03 ; Error out if error. XCHG DI,CX ; MOV AL,ES:[BX+DI] ; Get the odd memory byte. XCHG DI,CX ; MOV [XMSwordByte],AL ; Set the moved word. MOV AH,0BH ; Set the XMS move, function code. MOV SI,OFFSET XMSwordPUT ; Set address of the move structure. PUSH BX ; CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler. POP BX ; DEC AX ; Check for errors. JNZ MemToXMS03 ; Error out if error. MemToXMS02: JCXZ MemToXMS04 ; Avoid a zero byte move. MOV XMSmainPUT.Length,CX ; Set length for the move. MOV XMSmainPUT.SrcOffset,BX ; Set Memory address. MOV XMSmainPUT.SrcOffsetX,ES ; MOV XMSmainPUT.DestOffset,DX ; Set XMS address. MOV XMSmainPUT.DestOffsetX,DI ; MOV AH,0BH ; Set the XMS move, function code. MOV SI,OFFSET XMSmainPUT ; Set address of the move structure. CALL DWORD PTR [XMSfunctAdr] ; Call the XMS handler. DEC AX ; Check for errors. JZ MemToXMS05 MemToXMS03: MOV AX,XMSmemError ; Set error code if error. JMP MemToXMS05 ; MemToXMS04: XOR AX,AX ; MemToXMS05: POP DS POP ES POP DI POP SI POP DX POP CX POP BX POP BP RET ; Exit endproc MemToXMS SUBTTL Last Page PAGE+ pwrlolvl_TEXT ENDS END xmem.asm --------------------- END -------------------------------------- xmemc.c ---------------------------- START ------------------------- /* Copyright 1994 Alec Russell, ALL rights reserved Permission granted to use as you wish. Slightly higher level xms calls than xmem.asm */ #include #include #include #include #include xms_head_t xms_head={0}; // set handle to zero /* ---------------------- alloc_xms() ----------------- February 19,1994 */ short alloc_xms(unsigned short far *size) // size in 16k blocks { return(XMS_alloc(0, size)); } /* ---------------------- xms_to_mem() ---------------- February 19,1994 */ short xms_to_mem(unsigned short handle, void far *p, unsigned long off, unsigned short n) { unsigned short block, boff; block=off >> XMSBLOCKSHIFT; boff=off - (block << XMSBLOCKSHIFT); return(XMStoMem(handle, block, boff, n, p)); } /* ---------------------- mem_to_xms() ---------------- February 19,1994 */ short mem_to_xms(unsigned short handle, void far *p, unsigned long off, unsigned short n) { unsigned short block, boff; block=off >> XMSBLOCKSHIFT; boff=off - (block << XMSBLOCKSHIFT); return(MemToXMS(handle, block, boff, n, p)); } /* ---------------------- qalloc_xms() -------------------- March 8,1994 */ xms_node_t *qalloc_xms(unsigned long size) { xms_node_t *node=NULL; xms_node_t *t1; if ( size <= xms_head.avail ) { // look for existing node t1=xms_head.next; while ( t1 ) { if ( t1->used == 0 && t1->size >= size ) { t1->off=0; t1->used=1; node=t1; break; } else t1=t1->next; } if ( node == NULL ) // didn't find existing node { node=malloc(sizeof(xms_node_t)); if ( node ) { node->off=0; node->used=1; node->size=size; node->next=NULL; node->start=xms_head.next_off; xms_head.avail-=size; xms_head.next_off+=size; if ( xms_head.next == NULL ) { xms_head.next=node; } else { t1=xms_head.next; while ( t1->next ) t1=t1->next; t1->next=node; } } else pr2("out of near mem in qalloc_xms"); } } else pr2("out of xms mem in qalloc size %lu avail %lu", size, xms_head.avail); return(node); } /* ---------------------- qfree_xms() --------------------- March 8,1994 */ void qfree_xms(xms_node_t *node) { xms_node_t *t1; if ( xms_head.next ) { t1=xms_head.next; while ( t1 != node && t1 ) t1=t1->next; if ( t1 ) { t1->used=0; } else pr2("ERROR didn't find node qfree"); } else { pr2("ATTEMPTED to qfree empty list"); } } /* ---------------------- xms_open() ---------------------- March 8,1994 */ xms_node_t *xms_open(char *file) { int i; xms_node_t *node=NULL; FILE *fp; char *buffer; unsigned long off; fp=fopen(file, "rb"); if ( fp ) { node=qalloc_xms(filelength(fileno(fp))); if ( node ) { buffer=malloc(4096); if ( buffer ) { off=0l; while ( (i=fread(buffer, 1, 4096, fp)) ) { mem_to_xms(xms_head.handle, (char far *)buffer, off+node->start, i); off+=i; } free(buffer); } else pr2("out of mem in xms_open 1"); } fclose(fp); } else pr2("ERROR opening %s in xms_open", file); return(node); } /* ---------------------- xms_read() ---------------------- March 8,1994 */ short xms_read(void far *buffer, unsigned short n, xms_node_t *node) { if ( node->off >= node->size ) return 0; if ( n+node->off > node->size ) n=node->size - node->off; xms_to_mem(xms_head.handle, buffer, node->start+node->off, n); node->off+=n; return(n); } /* ---------------------- xms_write() ---------------------- March 8,1994 */ short xms_write(void far *buffer, unsigned short n, xms_node_t *node) { if ( node->off >= node->size ) return 0; if ( n+node->off > node->size ) n=node->size - node->off; mem_to_xms(xms_head.handle, buffer, node->start+node->off, n); node->off+=n; return(n); } /* ---------------------- xms_tell() ---------------------- March 8,1994 */ long xms_tell(xms_node_t *node) { return node->off; } /* ---------------------- xms_seek() ---------------------- March 8,1994 */ short xms_seek(xms_node_t *node, long off, short whence) { short err=0; switch ( whence ) { case SEEK_SET: if ( off < 0l || off > node->size ) err=1; else node->off=off; break; case SEEK_END: if ( off > 0l || (node->size + off) < 0l ) err=1; else node->off=node->size + off; break; case SEEK_CUR: if ( node->off + off < 0l || node->off + off > node->size ) err=1; else node->off+=off; break; } return(err); } /* ---------------------- xms_close() --------------------- March 8,1994 */ void xms_close(xms_node_t *node) { qfree_xms(node); } /* ---------------------- init_xms() ---------------------- March 8,1994 */ short init_xms(unsigned short min_blocks) { unsigned short blocks; blocks=XMSblk_available(); if ( blocks >= min_blocks ) { memset(&xms_head, 0, sizeof(xms_head_t)); if ( (xms_head.handle=alloc_xms(&blocks)) ) { pr2("blocks minus by = %u", blocks); min_blocks-=blocks; xms_head.avail=xms_head.total=(unsigned long)min_blocks*XMSBLOCK; blocks=min_blocks; } else blocks=0; } else blocks=0; return(blocks); } /* ---------------------- deinit_xms() -------------------- March 8,1994 */ void deinit_xms(void) { xms_node_t *t1, *t2; if ( xms_head.handle ) { XMS_dealloc(xms_head.handle); if ( xms_head.next ) { t1=xms_head.next; t2=t1->next; while ( t1 ) { free(t1); t1=t2; t2=t1->next; } } memset(&xms_head, 0, sizeof(xms_head_t)); } } /* --------------------------- end of file ------------------------- */ /* Not sure how to use this? call init_xms(x) to allocate a big chunk of xms. x is in 'blocks' of 16Kb. Pick X big enough to buffer all the files you want to place in xms. call xms_open("filename); for each file to be buffered. This copies the file int xms. then use xms_read(), xms_write(), and xms_seek() to read the file from xms instead of disk. call deinit_xms() just before exit to clean up. You can also use the lower level calls directly. */ xmemc.c ---------------------------- END -------------------------