
         ; Function must be declared PUBLIC so the linker
         ; can find it

         PUBLIC   ALLOCATE


         ; EXTRN declarations for Clipper internal routines
         ; and MACRO definitions

         INCLUDE  EXTENDA.MAC


         ; Low-level Clip-On routines which do the actual work

         EXTRN    _CO_HEXASM:FAR    ; Converts number to
                                    ; hexadecimal string
         EXTRN    _CO_ALLOCMEM:FAR  ; Allocates memory
         EXTRN    _CO_FREEMEM:FAR   ; Releases memory


;*******************************************
CODESEG  SEGMENT  BYTE 'CODE'
         ASSUME   CS:CODESEG

NULLSTR  DB       0                 ; Null string for error return

;-------------------------------------------
;
; This procedure is a memory allocator
; callable from Clipper.
;
;-------------------------------------------
;
;     SYNTAX:  memvar = ALLOCATE( <expN> )
;
; PARAMETERS:  <expN> = number of bytes to allocate
;
;    RETURNS:  segment address of allocated memory
;              as a hexadecimal string
;
;              offset address is 0 (not returned)
;
;--------------------
ALLOCATE PROC     FAR
         PUSH     BP            ; Save Clipper's registers
         MOV      BP,SP
         PUSH     DS
         PUSH     ES


         ; Step 1.

         ; Make sure at least one parameter has been passed
         ; by calling _PARINFO

         GET_PCOUNT               ; PCOUNT returned in AX
         OR       AX,AX           ; Is PCOUNT 0?
         JZ       ALLOC_ERR       ; Yes, so return error

         ; Step 2.

         ; PCOUNT greater than zero, so get parameter 1
         ; as long integer in AX:BX

         GET_LONG 1               ; get parameter in AX:BX

         ; Step 3.

         ; Parameters require no further processing, so
         ; we move on to Step 4.

         ; Step 4.
 
         ; Pass parameters to work routine (_CO_ALLOCMEM).

         PUSH     AX
         PUSH     BX

         ;  parameters for _CO_ALLOCMEM are now on the top of the stack

         CALL     _CO_ALLOCMEM    ; returns pointer in AX:BX
         ADD      SP,4

         ; Step 5.

         ; Receive and evaluate results from low-level routine.

         OR       AX,AX           ; was null pointer returned?
         JZ       ALLOC_ERR       ; yes, return error

         ; Step 6.

         ; Convert segment address in AX to hexadecimal string
         ; which we will return to Clipper.

         ; Here we call another low-level routine, _CO_HEXASM,
         ; which returns a pointer to a hexadecimal string.

         XOR      BX,BX
         PUSH     BX              ; PUSH a word of zeroes
         PUSH     AX              ; push segment for _CO_HEXASM
         CALL     _CO_HEXASM      ; AX:BX now has address
                                  ; of hex string to return
         ADD      SP,4
         JMP      SHORT ALLOC_EXIT


ALLOC_ERR:
         ; Error return--return address of NULLSTR,
         ; defined above

         MOV      BX,OFFSET CS:NULLSTR     ; return NULL pointer
         MOV      AX,CS

ALLOC_EXIT:
 
         ; Step 7.

         ; Return results to Clipper, but first--
 
         ; RESTORE CLIPPER'S REGISTERS!

         POP      ES
         POP      DS
         POP      BP

         ; Now return the value

         RET_CHAR AX,BX           ; return char pointer
         RET

ALLOCATE ENDP
;---------------------------------------------
CODESEG  ENDS
;************************************************
         END

